线程间同步互斥
朱果果 人气:1一、实现线程间同步互斥的操作:
1、线程间同步 ==== 有序执行
法1、多个信号量
法2、条件变量+互斥锁 ===>broadcast signal
2、线程间互斥 ==== "你死我活"
法1、单个信号量
法2、互斥锁
//1、互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。 //2、同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。 //3、同步其实已经实现了互斥,所以同步是一种更为复杂的互斥。 //4、互斥是一种特殊的同步。
二、为什么要实现同步互斥
保护临界资源
即全局变量
pthread_create之前的成为 全局资源 =====>当有线程操作全局资源的时候 ===>变为临界资源
三、代码示例
1、多个线程实现同步,定义多个信号量
1 #include<stdio.h> 2 #include <pthread.h> 3 #include <semaphore.h> 4 5 6 #define N 64 7 typedef struct message{ 8 char buf[N]; 9 int len; 10 }msg_t; 11 12 sem_t sem_reverse; //定义用于逆置的信号量 13 sem_t sem_printf; //定义用于打印的信号量 14 15 void* reverse_msgbuf(void* arg) 16 { 17 msg_t *msg = (msg_t *)arg; 18 int i = 0; 19 char tmp; 20 while(1){ 21 sem_wait(&sem_reverse); 22 printf("reverse_msgbuf -------------\n"); 23 //printf("hello reverse_msgbuf.\n"); 24 #if 1 25 for(i = 0; i < msg->len/2; i ++){ 26 tmp = msg->buf[i]; 27 msg->buf[i] = msg->buf[msg->len - i - 1]; 28 msg->buf[msg->len - i -1] = tmp; 29 } 30 #endif 31 sleep(1); 32 printf("reverse_msgbuf :%s\n",msg->buf); 33 sem_post(&sem_printf); 34 } 35 } 36 37 void* printf_msgbuf(void* arg) 38 { 39 msg_t *msg = (msg_t *)arg; 40 while(1){ 41 sem_wait(&sem_printf); 42 printf("printf_msgbuf :***********\n"); 43 printf("printf_msgbuf :%s\n",msg->buf); 44 sem_post(&sem_reverse); 45 } 46 } 47 48 int main(int argc, const char *argv[]) 49 { 50 msg_t msg = {"123456789",9}; 51 pthread_t tid[2]; 52 53 //初始化信号量 54 sem_init(&sem_reverse,0,1); //value=1,表示有资源可用,即让reverse先执行 55 sem_init(&sem_printf,0,0); //实现先逆置在打印,先逆置在打印,以此循环 56 57 pthread_create(&tid[0],NULL,reverse_msgbuf,(void *)&msg); 58 pthread_create(&tid[1],NULL,printf_msgbuf,(void *)&msg); 59 60 pause(); 61 62 return 0; 63 }
同步是在互斥的基础上实现有序。
2、互斥锁实现线程互斥
1 /************************************************************************* 2 # FileName : flaglock.c 3 # Author : fengjunhui 4 # Email : 18883765905@163.com 5 ************************************************************************/ 6 7 #include<stdio.h> 8 #include <pthread.h> 9 10 #define N 64 11 typedef struct message{ 12 char buf[N]; 13 int len; 14 }msg_t; 15 16 pthread_mutex_t mymutex; 17 18 void* reverse_msgbuf(void* arg) 19 { 20 msg_t *msg = (msg_t *)arg; 21 int i = 0; 22 char tmp; 23 while(1){ 24 pthread_mutex_lock(&mymutex); 25 for(i = 0; i < msg->len/2; i ++){ 26 tmp = msg->buf[i]; 27 msg->buf[i] = msg->buf[msg->len - i - 1]; 28 msg->buf[msg->len - i -1] = tmp; 29 } 30 pthread_mutex_unlock(&mymutex); 31 } 32 } 33 34 void* printf_msgbuf(void* arg) 35 { 36 msg_t *msg = (msg_t *)arg; 37 while(1){ 38 pthread_mutex_lock(&mymutex); 39 printf("buf :%s\n",msg->buf); 40 pthread_mutex_unlock(&mymutex); 41 sleep(1); 42 } 43 } 44 45 int main(int argc, const char *argv[]) 46 { 47 msg_t msg = {"123456789",9}; 48 49 pthread_t tid[2]; 50 pthread_mutex_init(&mymutex,NULL); 51 52 pthread_create(&tid[0],NULL,reverse_msgbuf,(void *)&msg); 53 pthread_create(&tid[1],NULL,printf_msgbuf,(void *)&msg); 54 55 pause(); 56 57 return 0; 58 }
互斥是一种特殊的同步
3、互斥锁 + 条件变量 实现同步互斥
1)mutex + pthread_cond + pthread_cond_broadcast
//pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。 //pthread_cond_wait() 必须与pthread_mutex 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。 //当其他线程通过pthread_cond_signal()或pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。
1 /************************************************************************* 2 # FileName : flaglock.c 3 # Author : fengjunhui 4 # Email : 18883765905@163.com 5 ************************************************************************/ 6 7 #include<stdio.h> 8 #include <pthread.h> 9 10 #define N 64 11 typedef struct message{ 12 char buf[N]; 13 int len; 14 // int busy_flag; 15 }msg_t; 16 17 int flag = 0; //定义一个flag,保证同步,reverse先执行 18 pthread_mutex_t mymutex; 19 pthread_cond_t mycond = PTHREAD_COND_INITIALIZER; 20 21 void* reverse_msgbuf(void* arg) 22 { 23 msg_t *msg = (msg_t *)arg; 24 int i = 0; 25 char tmp; 26 while(1){ 27 pthread_mutex_lock(&mymutex); //先上锁,以保护条件 28 printf("reverse_msgbuf -------------\n"); 29 while(flag != 0){ //flag不满足,即还没轮到我执行,则执行pthread_cond_wait 30 pthread_cond_wait(&mycond,&mymutex); //阻塞并释放锁,当条件变化后,唤醒阻塞并加锁,执行下面的代码 31 } 32 //printf("hello reverse_msgbuf.\n"); 33 #if 1 34 for(i = 0; i < msg->len/2; i ++){ 35 tmp = msg->buf[i]; 36 msg->buf[i] = msg->buf[msg->len - i - 1]; 37 msg->buf[msg->len - i -1] = tmp; 38 } 39 #endif 40 printf("reverse_msgbuf :%s\n",msg->buf); 41 flag = 1; 42 pthread_mutex_unlock(&mymutex); 43 pthread_cond_broadcast(&mycond); //唤醒所以阻塞的线程,可以来抢锁了(但有时我们需要一些线程继续wait) 44 } 45 } 46 47 void* printf_msgbuf(void* arg) 48 { 49 msg_t *msg = (msg_t *)arg; 50 while(1){ 51 pthread_mutex_lock(&mymutex); 52 printf("printf_msgbuf :***********\n"); 53 while(flag != 1){ 54 pthread_cond_wait(&mycond,&mymutex); 55 } 56 printf("printf_msgbuf :%s\n",msg->buf); 57 flag = 0; 58 pthread_mutex_unlock(&mymutex); 59 pthread_cond_broadcast(&mycond); 60 } 61 } 62 63 int main(int argc, const char *argv[]) 64 { 65 //msg_t msg = {"123456789",9,0}; 66 msg_t msg = {"123456789",9}; 67 68 pthread_t tid[2]; 69 70 pthread_cond_init(&mycond,NULL); 71 pthread_mutex_init(&mymutex,NULL); 72 73 pthread_create(&tid[0],NULL,reverse_msgbuf,(void *)&msg); 74 pthread_create(&tid[1],NULL,printf_msgbuf,(void *)&msg); 75 76 pause(); 77 78 return 0; 79 }
当有多个线程时,使用pthread_cond_broadcast会唤醒所有阻塞的线程,因此不能高效保证其同步性。
2)mutex + pthread_cond + pthread_cond_signal
//pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行 //.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。 //pthread_cond_signal只给一个线程发信号。 //假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。 //如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。。
1 /************************************************************************* 2 # FileName : flaglock.c 3 # Author : fengjunhui 4 # Email : 18883765905@163.com 5 ************************************************************************/ 6 7 #include<stdio.h> 8 #include <pthread.h> 9 10 #define N 64 11 typedef struct message{ 12 char buf[N]; 13 int len; 14 // int busy_flag; 15 }msg_t; 16 17 pthread_mutex_t mymutex; 18 pthread_cond_t mycond_reverse = PTHREAD_COND_INITIALIZER; 19 pthread_cond_t mycond_printf = PTHREAD_COND_INITIALIZER; 20 21 void* reverse_msgbuf(void* arg) 22 { 23 msg_t *msg = (msg_t *)arg; 24 int i = 0; 25 char tmp; 26 while(1){ 27 pthread_mutex_lock(&mymutex); 28 pthread_cond_wait(&mycond_reverse,&mymutex); 29 printf("reverse_msgbuf -------------\n"); 30 #if 1 31 for(i = 0; i < msg->len/2; i ++){ 32 tmp = msg->buf[i]; 33 msg->buf[i] = msg->buf[msg->len - i - 1]; 34 msg->buf[msg->len - i -1] = tmp; 35 } 36 #endif 37 printf("reverse_msgbuf :%s\n",msg->buf); 38 pthread_mutex_unlock(&mymutex); 39 } 40 } 41 42 void* printf_msgbuf(void* arg) 43 { 44 msg_t *msg = (msg_t *)arg; 45 while(1){ 46 pthread_mutex_lock(&mymutex); 47 pthread_cond_wait(&mycond_printf,&mymutex); 48 printf("printf_msgbuf :***********\n"); 49 printf("printf_msgbuf :%s\n",msg->buf); 50 pthread_mutex_unlock(&mymutex); 51 } 52 } 53 54 int main(int argc, const char *argv[]) 55 { 56 //msg_t msg = {"123456789",9,0}; 57 msg_t msg = {"123456789",9}; 58 59 pthread_t tid[2]; 60 61 pthread_cond_init(&mycond_printf,NULL); 62 pthread_cond_init(&mycond_reverse,NULL); 63 pthread_mutex_init(&mymutex,NULL); 64 65 pthread_create(&tid[0],NULL,reverse_msgbuf,(void *)&msg); 66 pthread_create(&tid[1],NULL,printf_msgbuf,(void *)&msg); 67 68 while(1){ 69 pthread_cond_signal (&mycond_printf); //唤醒对应阻塞的线程 70 sleep(1); 71 pthread_cond_signal (&mycond_reverse); 72 sleep(1); 73 //pthread_cond_signal (&xxx_xxx); 可以添加其他线程,实现多线程同步互斥 74 } 75 76 pause(); 77 78 return 0; 79 }
先将pthread_cond_signal注释掉,看看会有什么现象
两个线程都发送阻塞进入了睡眠,
疑问:创建线程时,线程运行进入阻塞,为什么代码能接着运行,而不是阻塞在阻塞处,不像下执行。
原因:在线程进入阻塞后,会自动释放CPU控制权,进入阻塞。只有当中断发生时,才会使线程从阻塞中跳出,即pthread_cond_signal唤醒阻塞线程
使用pthread_cond_signal唤醒指定的条件阻塞线程
加载全部内容