详解linux多线程——互斥锁、条件变量、读写锁、自旋锁、信号量( 二 )

需要C/C++ linux服务器架构师学习资料私信“资料”(资料包括C/C++ , Linux , golang技术 , Nginx , ZeroMQ , MySQL , redis , fastdfs , MongoDB , ZK , 流媒体 , CDN , P2P , K8S , Docker , TCP/IP , 协程 , DPDK , ffmpeg等) , 免费分享

详解linux多线程——互斥锁、条件变量、读写锁、自旋锁、信号量

文章插图
 
二、条件变量(同步)
  与互斥锁不同 , 条件变量是用来等待而不是用来上锁的 。条件变量用来自动阻塞一个线程 , 直 到某特殊情况发生为止 。通常条件变量和互斥锁同时使用 。
  条件变量使我们可以睡眠等待某种条件出现 。条件变量是利用线程间共享的全局变量进行同步 的一种机制 , 主要包括两个动作:
一个线程等待"条件变量的条件成立"而挂起;
另一个线程使 “条件成立”(给出条件成立信号) 。
【原理】:
  条件的检测是在互斥锁的保护下进行的 。线程在改变条件状态之前必须首先锁住互斥量 。如果一个条件为假 , 一个线程自动阻塞 , 并释放等待状态改变的互斥锁 。如果另一个线程改变了条件 , 它发信号给关联的条件变量 , 唤醒一个或多个等待它的线程 , 重新获得互斥锁 , 重新评价条件 。如果两进程共享可读写的内存 , 条件变量 可以被用来实现这两进程间的线程同步 。
【条件变量的操作流程如下】:
1. 初始化:init()或者pthread_cond_tcond=PTHREAD_COND_INITIALIER;属性置为NULL;
2. 等待条件成立:pthread_wait , pthread_timewait.wait()释放锁,并阻塞等待条件变量为真 timewait()设置等待时间,仍未signal,返回ETIMEOUT(加锁保证只有一个线程wait);
3. 激活条件变量:pthread_cond_signal,pthread_cond_broadcast(激活所有等待线程)
4. 清除条件变量:destroy;无线程等待,否则返回EBUSY清除条件变量:destroy;无线程等待,否则返回EBUSY
#include <pthread.h>// 初始化条件变量int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);// 阻塞等待int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);// 超时等待int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);// 解除所有线程的阻塞int pthread_cond_destroy(pthread_cond_t *cond);// 至少唤醒一个等待该条件的线程int pthread_cond_signal(pthread_cond_t *cond);// 唤醒等待该条件的所有线程int pthread_cond_broadcast(pthread_cond_t *cond);1、线程的条件变量实例1
  Jack开着一辆出租车来到一个站点停车 , 看见没人就走了 。过段时间 , Susan来到站点准备乘车 , 但是没有来 , 于是就等着 。过了一会Mike开着车来到了这个站点 , Sunsan就上了Mike的车走了 。如图所示:
详解linux多线程——互斥锁、条件变量、读写锁、自旋锁、信号量

文章插图
 
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>pthread_cond_t taxicond = PTHREAD_COND_INITIALIZER;pthread_mutex_t taximutex = PTHREAD_MUTEX_INITIALIZER;void *traveler_arrive(void *name){char *p = (char *)name;printf ("Travelr: %s need a taxi now!n", p);// 加锁 , 把信号量加入队列 , 释放信号量pthread_mutex_lock(&taximutex);pthread_cond_wait(&taxicond, &taximutex);pthread_mutex_unlock(&taximutex);printf ("traveler: %s now got a taxi!n", p);pthread_exit(NULL);}void *taxi_arrive(void *name){char *p = (char *)name;printf ("Taxi: %s arrives.n", p);// 给线程或者条件发信号 , 一定要在改变条件状态后再给线程发信号pthread_cond_signal(&taxicond);pthread_exit(NULL);}int main (int argc, char **argv){char *name;pthread_t thread;pthread_attr_t threadattr; // 线程属性pthread_attr_init(&threadattr);// 线程属性初始化// 创建三个线程name = "Jack";pthread_create(&thread, &threadattr, taxi_arrive, (void *)name);sleep(1);name = "Susan";pthread_create(&thread, &threadattr, traveler_arrive, (void *)name);sleep(1);name = "Mike";pthread_create(&thread, &threadattr, taxi_arrive, (void *)name);sleep(1);return 0;}2、线程的条件变量实例2
  Jack开着一辆出租车来到一个站点停车 , 看见没人就等着 。过段时间 , Susan来到站点准备乘车看见了Jack的出租车 , 于是就上去了 。过了一会Mike开着车来到了这个站点 , 看见没人救等着 。如图所示:


推荐阅读