Linux-----线程同步(条件变量)

打印 上一主题 下一主题

主题 959|帖子 959|积分 2877

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
 目录
相关API
restrict关键字
线程间条件切换函数
条件变量pthread_cond_t
案例


在前面的锁的基础上进一步进步线程同步效率,也就是两个线程只用锁去实行的话依然会存在资源竞争的情况,也就是抢锁,这里就必要在锁的这边加上限制,也就是条件变量,有了条件变量的加持,就可以很好的控制线程与线程之间的协同。 

相关API

restrict关键字

restrict是一个C99标准引入的关键字,用于修饰指针,它的作用是告诉编译器,被修饰的指针是编译器所知的唯一一个可以在其作用域内用来访问指针所指向的对象的方法。如许一来,编译器可以放心地实行代码优化,由于不存在其他的别名(即其他指向同一内存地区的指针)会影响到这块内存的状态。
restrict声明了一种约定,主要目的是允许编译器在天生代码时做出优化假设,而不是在程序的差别部门间强制实行内存访问的规则。程序员必要确保遵守restrict的约定,编译器则依赖这个约定来进行优化。如果restrict约定被违背,可能导致未定义行为。
函数参数使用restrict修饰,相称于约定:函数实行期间,该参数指向的内存地区不会被别的指针修改。
线程间条件切换函数

如果必要两个线程协同工作,可以使用条件变量完成线程切换。查看文档可得:
  1. #include <pthread.h>
  2. /**
  3. * @brief 调用该方法的线程必须持有mutex锁。调用该方法的线程会阻塞并临时释放mutex锁,并等待其他线程调用pthread_cond_signal或pthread_cond_broadcast唤醒。被唤醒后该线程会尝试重新获取mutex锁。
  4. *
  5. * @param cond 指向条件变量的指针。条件变量用于等待某个条件的发生。通过某一cond等待的线程需要通过同一cond的signal唤醒
  6. * @param mutex 与条件变量配合使用的互斥锁的指针。在调用pthread_cond_wait之前,线程必须已经获得了这个互斥锁。
  7. * @return int 成功时返回0;失败时返回错误码,而非-1。错误码可能包括EINVAL、EPERM等,具体取决于错误的性质。
  8. */
  9. int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
  10. /**
  11. * @brief 同pthread_cond_wait相似,但是它添加了超时机制。如果在指定的abstime时间内条件变量没有被触发,函数将返回一个超时错误(ETIMEDOUT)。
  12. *
  13. * @param cond 指向条件变量的指针
  14. * @param mutex 与条件变量配合使用的互斥锁的指针
  15. * @param abstime 指向timespec结构的指针,表示等待条件变量的绝对超时时间。timespec结构包含秒和纳秒两部分,指定了从某一固定点(如UNIX纪元,1970年1月1日)开始的时间。
  16. * @return int 成功时返回0;如果超时则返回ETIMEDOUT;其他错误情况返回相应的错误码。
  17. */
  18. int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
  19. /**
  20. * @brief 唤醒因cond而阻塞的线程,如果有多个线程因为cond阻塞,那么随机唤醒一个。如果没有线程在等待,这个函数什么也不做。
  21. *
  22. * @param cond 指向条件变量的指针
  23. * @return int 成功时返回0;失败时返回错误码
  24. */
  25. int pthread_cond_signal(pthread_cond_t *cond);
  26. /**
  27. * @brief 唤醒所有正在等待条件变量cond的线程。如果没有线程在等待,这个函数什么也不做。
  28. *
  29. * @param cond 指向条件变量的指针。
  30. * @return int 成功时返回0;失败时返回错误码。
  31. */
  32. int pthread_cond_broadcast(pthread_cond_t *cond);
复制代码

  • 使用条件变量时,通常涉及到一个或多个线程等待“条件变量”代表的条件成立,而别的一些线程在条件成立时触发条件变量。
  • 条件变量的使用必须与互斥锁配合,以保证对共享资源的访问是互斥的。
  • 条件变量提供了一种线程间的通讯机制,允许线程以无竞争的方式等待特定条件的发生。
条件变量pthread_cond_t

 pthread_cond_t是一个条件变量,它是线程间同步的另一种机制。与pthread_mutex_t相同,它也定义在头文件<pthreadtypes.h>中,其声明如下。
  1. typedef union
  2. {
  3.   struct __pthread_cond_s __data;
  4.   char __size[__SIZEOF_PTHREAD_COND_T];
  5.   __extension__ long long int __align;
  6. } pthread_cond_t;
复制代码

案例

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. // 同步队列?
  5. #define BUFFER_SIZE 10
  6. int buffer[BUFFER_SIZE];
  7. int count = 0;
  8. // 互斥锁
  9. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  10. // 初始化调解笔录
  11. static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  12. // 生产者线程函数
  13. void* producer_fun(void* args) {
  14.     int i = 1;
  15.     while (1)
  16.     {
  17.         // 使用共同变量,使用互斥锁
  18.         pthread_mutex_lock(&mutex);
  19.         // 如果缓冲区慢了就要暂停放入
  20.         if (count == BUFFER_SIZE) {
  21.             pthread_cond_wait(&cond, &mutex);
  22.         }
  23.         printf("生产者写入%d\n", i);
  24.         buffer[count++] = i++;
  25.         // 唤醒消费者
  26.         pthread_cond_signal(&cond);
  27.         // 最后释放锁
  28.         pthread_mutex_unlock (&mutex);
  29.     }
  30.    
  31. }
  32. void* consumer_fun(void* args) {
  33.     while (1)
  34.     {
  35.         pthread_mutex_lock(&mutex);
  36.         // 数据读完了
  37.         if (count == 0) {
  38.             pthread_cond_wait(&cond, &mutex);
  39.         }
  40.         printf("消费者收到数据%d\n", buffer[--count]);
  41.         // 唤醒生产者
  42.         pthread_cond_signal(&cond);
  43.         
  44.         pthread_mutex_unlock(&mutex);
  45.     }
  46.    
  47. }
  48. int main(int argc, char const *argv[])
  49. {
  50.     pthread_t producer, consumer;
  51.     // 创建线程
  52.     pthread_create(&producer, NULL, producer_fun, NULL);
  53.     pthread_create(&consumer, NULL, consumer_fun, NULL);
  54.     // 主线程要挂起等待子线程
  55.     pthread_join(producer, NULL);
  56.     pthread_join(consumer, NULL);
  57.     return 0;
  58. }
复制代码

 上面这个写法还是会存在资源竞争的情况,也就是抢锁,实际上并不是生产者生产后消费者马上实行,而是相互竞争的。下面是修改后:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. // 同步队列?
  5. #define BUFFER_SIZE 10
  6. int buffer[BUFFER_SIZE];
  7. int count = 0;
  8. // 互斥锁
  9. static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  10. // 初始化调解笔录
  11. static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  12. // 生产者线程函数
  13. void* producer_fun(void* args) {
  14.     int i = 1;
  15.     // 使用共同变量,使用互斥锁
  16.     pthread_mutex_lock(&mutex);
  17.     while (1)
  18.     {
  19.         // 如果缓冲区慢了就要暂停放入
  20.         if (count == BUFFER_SIZE) {
  21.             pthread_cond_wait(&cond, &mutex);
  22.             
  23.         }
  24.         printf("生产者写入%d\n", i);
  25.         buffer[count++] = i++;
  26.         // 唤醒消费者
  27.         pthread_cond_signal(&cond);
  28.     }
  29.     // 最后释放锁
  30.     pthread_mutex_unlock (&mutex);
  31. }
复制代码
 这种做法,可以实现生产者生产完后知道队列满了,然后就消费者消费直到清空,如许子一轮一轮的实行,利益如下:
   

  


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表