线程的介绍及同步线程的使用

1.用父子进程来同时读取键盘和鼠标

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
        int fd = -1;
        int pid = -1;
        char buf[200];

        pid = fork();

        if(pid == 0)
        {
                fd = open("/dev/input/mouse0",O_RDONLY);//打开鼠标
                if(fd < 0)
                {
                        perror("open");
                        return -1;
                }
                while(1)
                {
                        memset(buf,0,sizeof(buf));
                        printf("before 鼠标 read\n");
                        //读取鼠标
                        read(fd,buf,5);//read默认是阻塞的
                        printf("鼠标读出的内容是:[%s]\n",buf);
                }
        }
        else if(pid > 0)
        {
                while(1)
                {
                        memset(buf,0,sizeof(buf));
                        printf("before 键盘 read\n");
                        //读取键盘键盘就是标准输入,stdin
                        read(0,buf,2);//read默认是阻塞的
                        printf("键盘读出的内容是:[%s]\n",buf);
                }
		}
        else
        {
                perror("fork");
                return -1;
        }

        return 0;
}

2.多进程的优缺点
(1)优点:CPU时分复用,单核心CPU可以实现宏观上的并行,实现多任务系统需求(多任务的系统需求是客观的)
(2)缺点:进程间切换开销大,进程间通信麻烦而且效率低,而线程就解决了这些麻烦。线程技术保留了进程技术实现多任务的他特性。线程的改进就是在线程间通信和切换上提升了效率。多线程在多核CPU上更有优势。
(3)用线程同时读取键盘和鼠标

#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

char buf[200];

void *func(void *arg)
{
        while(1)
        {
                memset(buf,0,sizeof(buf));
                printf("before 键盘 read\n");
                //读取键盘键盘就是标准输入,stdin
                read(0,buf,2);//read默认是阻塞的
                printf("键盘读出的内容是:[%s]\n",buf);

        }
}

int main(void)
{
        int fd = -1;
        int ret = -1;
        pthread_t th = -1;

        //int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        //                  void *(*start_routine) (void *), void *arg);
        ret = pthread_create(&th,NULL,func,NULL);	//创建一个线程
        if(ret != 0)
        {
                perror("pthread_create");
                return -1;
        }

        //主任务
        fd = open("/dev/input/mouse0",O_RDONLY);//打开鼠标
        if(fd < 0)
        {
                perror("open");
                return -1;
		}
        while(1)
        {
                memset(buf,0,sizeof(buf));
                printf("before 鼠标 read\n");
                //读取鼠标
                read(fd,buf,5);//read默认是阻塞的
                printf("鼠标读出的内容是:[%s]\n",buf);
        }
        
        return 0;
}

3.线程简介
(1)一种轻量级进程
(2)线程是参与内核调度的最小单元
(3)一个进程中可以有多个线程

4.线程技术的优势
(1)向进程一样可以被OS调度
(2)同一进程的多个线程之间很容易高效率通信
(3)在多核CPU架构下效率最大化

5.线程相关的函数
(1)pthread_create:主线程用来创建子线程
(2)pthread_join:主线程用来等待回收子线程
(3)pthread_detach:主线程用来分离子线程,分离后主线程不必再去回收子线程

6.线程取消
(1)pthread_cancel:一般是主线程调用该函数去取消(杀死)子进程。
(2)pthread_setcancelstate:子线程设置自己是否允许被取消
(3)pthread_setcanceltype:设置子线程取消模式

7.线程函数退出相关(线程自动退出)
(1)pthread_exit与return退出
(2)pthread_cleanup_push:给线程上锁
(3)pthread_cleanup_pop:给线程去锁

8.获取线程id
pthread_self

9.线程同步之信号量(实现计算一个字符串输入长度)

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>

char buf[500] = {0};
sem_t sem;
unsigned int flag = 0;

//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
        //int sem_wait(sem_t *sem);等待信号量被激活函数
        sem_wait(&sem);
        while(strncmp(buf,"end",3))
        {
                printf("本次输入了%ld个字符\n",strlen(buf));
                memset(buf,0,sizeof(buf));
                sem_wait(&sem);
        }
        pthread_exit(NULL);
}

int main()
{
        int ret = -1;
        pthread_t th = -1;

        //int sem_init(sem_t *sem, int pshared, unsigned int value);定义或初始化一个信号量
        sem_init(&sem,0,0);

        ret = pthread_create(&th,NULL,func,NULL);
        if(ret != 0)
        {
                printf("pthread_creat error");
                return -1;
        }

        printf("请输入一个字符串,以回车结束\n");
		while(scanf("%s",buf))
        {
                if(!strncmp(buf,"end",3))
                {
                        printf("程序结束\n");
                        flag = 1;
                        //int sem_post(sem_t *sem);激活信号量函数
                        sem_post(&sem);
                        break;
                }
                //主线程在收到用户输入的字符串并确认不是end后就去发信号量激活子线程来计数
                //子线程被阻塞,主线程可以激活,这就是线程同步问题,用信号量来实现
                sem_post(&sem);
        }
        //回收子线程
        printf("等待回收子线程\n");
        ret = pthread_join(th,NULL);
        if(ret != 0)
        {
                printf("回收失败\n");
                exit(-1);
        }
        printf("子线程回收成功\n");

        //int sem_destroy(sem_t *sem);信号量摧毁函数
        sem_destroy(&sem);

        return 0;
}

9.线程同步之互斥所
(1)什么是互斥锁:互斥锁有叫互斥量
(2)相关函数:pthread_mutex_init、pthread_mutex_destroy、pthread_mutex_lock、pthread_mutex_unlock
(3)互斥锁和信号量的关系:可以认为互斥锁是一种特殊的信号量
(4)互斥锁主要用来实现关键段保护
注意:当使用上面几个库函数查看man手册时,找不到这个手册项目是需要按照man手册:sudo apt install manpages-posix-dev

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <stdlib.h>

char buf[500] = {0};
pthread_mutex_t mutex;
unsigned int flag = 0;

//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
        sleep(1);
        while(flag != 1)
        {
                pthread_mutex_lock(&mutex);
                printf("本次输入了%ld个字符\n",strlen(buf));
                memset(buf,0,sizeof(buf));
                pthread_mutex_unlock(&mutex);
                sleep(1);
        }
        pthread_exit(NULL);
}

int main()
{
        int ret = -1;
        pthread_t th = -1;

        //int pthread_mutex_init(pthread_mutex_t *restrict mutex,
        //    const pthread_mutexattr_t *restrict attr);
        pthread_mutex_init(&mutex,NULL);
        ret = pthread_create(&th,NULL,func,NULL);
        if(ret != 0)
        {
                printf("pthread_creat error");
                return -1;
		}

        printf("请输入一个字符串,以回车结束\n");
        while(1)
        {
                //int pthread_mutex_lock(pthread_mutex_t *mutex);
                pthread_mutex_lock(&mutex);//上锁
                scanf("%s",buf);
                pthread_mutex_unlock(&mutex);//解锁
                if(!strncmp(buf,"end",3))
                {
                        printf("程序结束\n");
                        flag = 1;
                        break;
                }
                sleep(1);
        }
        //回收子线程
        printf("等待回收子线程\n");
        ret = pthread_join(th,NULL);
        if(ret != 0)
        {
                printf("回收失败\n");
                exit(-1);
        }
        printf("子线程回收成功\n");

        pthread_mutex_destroy(&mutex);

        return 0;
}

10.线程同步之条件变量
(1)相关函数pthread_cond_init、pthread_cond_destroy、pthread_cond_wait、pthread_cond_signal(只能唤醒一个)、pthread_cond_broadcast(可以唤醒多个)

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <stdlib.h>

char buf[500] = {0};
pthread_mutex_t mutex;
unsigned int flag = 0;
pthread_cond_t cond;

//子线程的作用是统计buf中的字符个数并打印
//子线程应该有个循环,循环中阻塞在等待主线程激活的时候,
//子线程被激活后就去获取buf中的字符长度,然后打印,完成后又被阻塞
void *func(void *arg)
{
        while(flag != 1)
        {
                pthread_mutex_lock(&mutex);
                //int pthread_cond_wait(pthread_cond_t *restrict cond,
                //      pthread_mutex_t *restrict mutex);
                pthread_cond_wait(&cond,&mutex);//条件成立才往下执行
                printf("本次输入了%ld个字符\n",strlen(buf));
                memset(buf,0,sizeof(buf));
                pthread_mutex_unlock(&mutex);
        }
        pthread_exit(NULL);
}

int main()
{
        int ret = -1;
        pthread_t th = -1;

        //int pthread_mutex_init(pthread_mutex_t *restrict mutex,
        //    const pthread_mutexattr_t *restrict attr);
        pthread_mutex_init(&mutex,NULL);
        //int pthread_cond_init(pthread_cond_t *restrict cond,
        //    const pthread_condattr_t *restrict attr);
        pthread_cond_init(&cond,NULL);
        ret = pthread_create(&th,NULL,func,NULL);
        if(ret != 0)
        {
                printf("pthread_creat error");
                return -1;
        }

        printf("请输入一个字符串,以回车结束\n");
        while(1)
        {
                //int pthread_mutex_lock(pthread_mutex_t *mutex);
                //pthread_mutex_lock(&mutex);//上锁
                scanf("%s",buf);
                //int pthread_cond_signal(pthread_cond_t *cond);
                pthread_cond_signal(&cond);
                pthread_mutex_unlock(&mutex);//解锁
                if(!strncmp(buf,"end",3))
                {
                        printf("程序结束\n");
                        flag = 1;
                        break;
                }
                sleep(1);
        }
        //回收子线程
        printf("等待回收子线程\n");
        //int pthread_join(pthread_t thread, void **retval);
        ret = pthread_join(th,NULL);
        if(ret != 0)
        {
                printf("回收失败\n");
                exit(-1);
        }
        printf("子线程回收成功\n");

        //int pthread_mutex_destroy(pthread_mutex_t *mutex);
        pthread_mutex_destroy(&mutex);
        //int pthread_cond_destroy(pthread_cond_t *cond);
        pthread_cond_destroy(&cond);

        return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值