线程同步之条件变量

简介:

一.概述:

    条件变量是线程同步的一种机制,它是通过一个条件,当条件满足时,唤醒一个线程,但条件不满足时,挂起该线程。由于同步是伴随着互斥的,所以条件变量一般都伴随着互斥锁。




二.相关函数:

(1).cond:pthread_cond_t  cond  =  PTHREAD_COND_INITIALIZER

     cond是一个全局变量,和mutex一样。

(2).pthread_cond_init函数:int  pthread_cond_init(pthread_cond_t  *restrict  cond, 

                                                                                   const  pthread_condattr_t  *restrict  attr)

attr参数:用于初始化cond,NULL表示缺省属性。weiNULL时和声明一个全局的cond一样。

返回值:成功返回0,失败返回错误号。

PS:restrict,C语言中的一种类型限定符(TypeQualifiers),用于告诉编译器,对象已经被指针所引用,不能通过除该指针外所有其他直接或间接的方式修改该对象的内容。

(3).phtread_cond_destroy函数:int  pthread_cond_destroy(pthread_cond_t *cond)

函数功能:销毁cond。

返回值:成功返回0,失败返回错误号。

(4).pthread_cond_timedwait函数:int  pthread_cond_timedwait(pthread_cond_t *restrict  cond, 

                                                                                                     pthread_mutex_t *restrict  mutex,

                                                                                                     const  struct timespaec *restrict abstime)

函数功能:将当前线程挂起,直到有信号将其唤醒或出现错误返回。

sbstime参数:等待超时时间,如果到达了abstime所指定的 时刻仍然没有别的线程来唤醒当前线程,就返回ETIMEDOUT。

返回值:成功返回0,失败返回错误号。

(5).pthread_cond_wait函数:int  pthread_cond_timedwait(pthread_cond_t *restrict  cond, 

                                                                                                     pthread_mutex_t *restrict  mutex)

函数功能:将当前线程挂起,直到有信号将其唤醒或出现错误返回。

返回值:成功返回0,失败返回错误号。

(6).pthread_cond_signal函数:int pthread_cond_signal(pthread_cond_t *cond)

函数功能:发出一个信号给用cond等待挂起的线程,使之进入就绪态。

返回值:成功返回0,失败返回错误号。

(7).pthread_cond_broadcastsignal函数:int pthread_cond_signal(pthread_cond_t *cond)

函数功能:发出一个信号给所有用cond等待挂起的线程,使它们都进入就绪态。

返回值:成功返回0,失败返回错误号。




三.相关代码:(生产者与消费者模型)(必须是生产者先生产,消费者再消费的顺序)

在没有加互斥锁和条件变量之前:

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<malloc.h>
  4 #include<pthread.h>
  5 
  6 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  7 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  8 
  9 typedef struct node
 10 {
 11     int _data;
 12     struct node* _next;
 13 }node_t, *node_p, **node_pp;
 14 
 15 node_p head = NULL;
 16 int g_data;                   //用于表示消费的数据
 17 
 18 node_p buy_node(int data)                                                                                                                                      
 19 {
 20     node_p tem = malloc(sizeof(node_t));
 21     if(tem)
 22     {   
 23         tem->_data = data;
 24         tem->_next = NULL;
 25         return tem;
 26     }
 27     return NULL;
 28 }
 29 
 30 
 31 void init_list(node_pp list)
 32 {
 33     *list = buy_node(0);
 34 }
 35 
 36 void head_push(node_p list, int data)
 37 {
 38     node_p tem = buy_node(data);
 39     tem->_next = list->_next;
 40     list->_next = tem;
 41 }
 42 
 43 int tail_pop(node_p list)
 44 {
 45     if(list->_next == NULL)
 46     {
 47         g_data = -1;
 48         return -1;
 49     }
 50 
 51     node_p tem = list;
 52     node_p del = NULL;
 53     while(tem->_next != NULL)
 54     {
 55         del = tem->_next;
 56         if(tem->_next->_next == NULL)
 57         {                                                                                                                                                      
 58             tem->_next = NULL;
 59         }
 60         else
 61         {   
 62             tem = tem->_next;
 63         }
 64     }
 65     
 66     g_data = del->_data;
 67     free(del);
 68     return 0;
 69 }
 70 
 71 void show_list(node_p list)
 72 {
 73     node_p tem = list;
 74     while(tem != NULL)
 75     {
 76         printf("%d  ",tem->_data);
 77         tem = tem->_next;
 78     }
 79     printf("\n");
 80 }
 81 
 82 void* product(void* ptr)
 83 {
 84     int i = 1;
 85     while(1)
 86     {
 87         head_push(head, i);
 88         sleep(1);
 89         printf("product data -> %d\n",i);
 90         i++;
 91     }
 92 }
 93 
 94 void* consumer(void* ptr)
 95 {
 96     while(1)
 97     {
 98         tail_pop(head);
 99         sleep(1);
100         printf("consumer data -> %d\n", g_data);
101     }
102 }
103 
104 
105 
106 
107 int main()
108 {
109     init_list(&head);
110 
111                                                                                                                                                                
112     pthread_t tid1, tid2;
113     pthread_create(&tid1, NULL, product, NULL);
114     pthread_create(&tid2,NULL, consumer, NULL);
115     pthread_join(tid1, NULL);
116     pthread_join(tid2, NULL);
117 
118     pthread_mutex_destroy(&lock);
119     pthread_cond_destroy(&cond);
120 
121 
122 //  int i = 1;
123 //  while(i <= 5)
124 //  {
125 //      head_push(head, i++);
126 //      show_list(head);
127 //  }
128 //  printf("-------------------------------------\n");
129 //  while(i >= 1)
130 //  {
131 //      tail_pop(head);
132 //      show_list(head);
133 //      i--;
134 //  }
135 
136     return 0;
137 }
138 
139 
140

执行结果:

wKioL1cZj16jCOs4AAA6xMMOTTA229.png

PS:可以看到结果为消费者先消费,而不是生产者先生产。



用互斥锁和条件变量:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<malloc.h>
  4 #include<pthread.h>
  5 
  6 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  7 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  8 
  9 typedef struct node
 10 {
 11     int _data;
 12     struct node* _next;
 13 }node_t, *node_p, **node_pp;
 14 
 15 node_p head = NULL;            //头指针
 16 int g_data;                   //用于表示消费的数据
 17 
 18 node_p buy_node(int data)
 19 {
 20     node_p tem = malloc(sizeof(node_t));
 21    
 
if(tem)                                                                                                                                                  
  
 22     {   
 23         tem->_data = data;
 24         tem->_next = NULL;
 25         return tem;
 26     }
 27     return NULL;
 28 }
 29 
 30 
 31 void init_list(node_pp list)
 32 {
 33     *list = buy_node(0);
 34 }
 35 
 36 void head_push(node_p list, int data)
 37 {
 38     node_p tem = buy_node(data);
 39     tem->_next = list->_next;
 40     list->_next = tem;
 41 }
 42 
 43 int tail_pop(node_p list)
 44 {
 45     if(list->_next == NULL)

 46     
{                                                                                                                                                        
  
 47         g_data = -1;
 48         return -1;
 49     }
 50     
 51     node_p tem = list;
 52     node_p del = NULL;
 53     while(tem->_next != NULL)
 54     {   
 55         del = tem->_next;
 56         if(tem->_next->_next == NULL)
 57         {   
 58             tem->_next = NULL;
 59         }
 60         else
 61         {   
 62             tem = tem->_next;
 63         }
 64     }
 65     
 66     g_data = del->_data;
 67     free(del);
 68     return 0;
 69 }
 70 
 71 void show_list(node_p list)
 72 {
 73     node_p tem = list;
 74     while(tem != NULL)
 75     {
 76         printf("%d  ",tem->_data);
 77         tem = tem->_next;
 78     }
 79     printf("\n");
 80 }
 81 
 82 void* product(void* ptr)
 83 {
 84     int i = 1;
 85     while(1)
 86     {
 87         pthread_mutex_lock(&lock);
 88         head_push(head, i);
 89         sleep(1);
 90         i++;
 91         pthread_mutex_unlock(&lock);
 92         printf("product data -> %d\n",i);
 93         pthread_cond_signal(&cond);     //生产一个就可以唤醒消费者了
 94     }
 95 }
 96 
 97 void* consumer(void* ptr)
 98 {
 99     while(1)
100     {
101         pthread_mutex_lock(&lock);
102         while(head->_next == NULL)      //注意要用while为不是if  因为可能会出现一个错误信号把
103         {                               //该线程唤醒,但链表内并没有数据的可能。 
104             pthread_cond_wait(&cond, &lock);
105         }
106         tail_pop(head);
107         sleep(1);
108         pthread_mutex_unlock(&lock);
109         printf("consumer data -> %d\n", g_data);
110     }
111 }
112 
113 
114 int main()
115 {
116     init_list(&head);
117 
118 
119     pthread_t tid1, tid2;
120     pthread_create(&tid1, NULL, product, NULL);
121     pthread_create(&tid2,NULL, consumer, NULL);
122     pthread_join(tid1, NULL);
123     pthread_join(tid2, NULL);
124 
125     pthread_mutex_destroy(&lock);
126     pthread_cond_destroy(&cond);
127 
128 
129//  int i = 1;                                                                                                                                               
130 //  while(i <= 5)
131 //  {
132 //      head_push(head, i++);
133 //      show_list(head);
134 //  }
135 //  printf("-------------------------------------\n");
136 //  while(i >= 1)
137 //  {
138 //      tail_pop(head);
139 //      show_list(head);
140 //      i--;
141 //  }
142 
143     return 0;
144 }
145 
146 
147                                                                                                                                                              
  
                                                                                                                                                
 147,0-1      底端

                                                                                                                                               
 129,1         82%

执行结果:

wKioL1cZlmfBE3JRAAA-bC2IiMk963.png










本文转自 ye小灰灰  51CTO博客,原文链接:http://blog.51cto.com/10704527/1766621,如需转载请自行联系原作者
目录
相关文章
|
存储 Java 测试技术
ThreadLocal:线程专属的变量
ThreadLocal:线程专属的变量
222 0
|
Java 开发者
解锁并发编程新姿势!深度揭秘AQS独占锁&ReentrantLock重入锁奥秘,Condition条件变量让你玩转线程协作,秒变并发大神!
【8月更文挑战第4天】AQS是Java并发编程的核心框架,为锁和同步器提供基础结构。ReentrantLock基于AQS实现可重入互斥锁,比`synchronized`更灵活,支持可中断锁获取及超时控制。通过维护计数器实现锁的重入性。Condition接口允许ReentrantLock创建多个条件变量,支持细粒度线程协作,超越了传统`wait`/`notify`机制,助力开发者构建高效可靠的并发应用。
303 0
|
Java 程序员 调度
【JavaEE】线程创建和终止,Thread类方法,变量捕获(7000字长文)
创建线程的五种方式,Thread常见方法(守护进程.setDaemon() ,isAlive),start和run方法的区别,如何提前终止一个线程,标志位,isinterrupted,变量捕获
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
279 6
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
存储 SQL Java
(七)全面剖析Java并发编程之线程变量副本ThreadLocal原理分析
在之前的文章:彻底理解Java并发编程之Synchronized关键字实现原理剖析中我们曾初次谈到线程安全问题引发的"三要素":多线程、共享资源/临界资源、非原子性操作,简而言之:在同一时刻,多条线程同时对临界资源进行非原子性操作则有可能产生线程安全问题。
446 1
|
存储 Python 容器
Node中的AsyncLocalStorage 使用问题之在Python中,线程内变量的问题如何解决
Node中的AsyncLocalStorage 使用问题之在Python中,线程内变量的问题如何解决
140 2
|
调度
线程操作:锁、条件变量的使用
线程操作:锁、条件变量的使用
151 1
|
存储 缓存 算法
同时使用线程本地变量以及对象缓存的问题
【7月更文挑战第15天】同时使用线程本地变量和对象缓存需小心处理以避免数据不一致、竞争条件及内存泄漏等问题。线程本地变量使各线程拥有独立存储,但若与对象缓存关联,可能导致多线程环境下访问旧数据。缺乏同步机制时,多线程并发修改缓存中的共享对象还会引起数据混乱。此外,若线程结束时未释放对象引用,可能导致内存泄漏。例如,在Web服务器场景下,若一更新缓存而另一线程仍获取旧数据,则可能返回错误信息;在图像处理应用中,若多线程无序修改算法对象则可能产生错误处理结果。因此,需确保数据一致性、避免竞争条件并妥善管理内存。
177 0

热门文章

最新文章