线程同步的方法—互斥锁、信号量和条件变量
来源:互联网 发布:厦门安胜网络怎么样 编辑:程序博客网 时间:2024/05/16 19:39
在说线程的同步异步之前,先说一下进程的同步与异步,因为线程的同步与异步基本上是一个概念,只是将进程之间的关系修改为线程之间的关系 。
1、同步:当一个进程/线程在执行某个请求的时候,请求的信息需要等一段时间才能够返回,那么该进程/线程就一直等待,直到请求的信息返回。
2、异步:当一个进程/线程在执行某个请求的时候,不必等待请求信息的返回,直接执行接下来的操作。不管其他进程/线程的状态。当有消息返回时系统会通知进程/线程进行处理,这样可以提高执行的效率。
简单来说:同步需要等待,异步不需要等待。
全局变量共享-》进程内所有的线程都可以操作全局变量。
例如:需要在函数线程中统计用户输入的单词个数,在主线程中获取用户输入,放入全局字符数组。
(1)互斥锁
允许程序员锁住某个对象,使得每次只能有一个线程访问他。为了控制关键代码的访问,必须在进入这段代码之前锁住一个互斥量,然后再完成操作之后解锁它。
用于互斥锁的基本函数:
#include<stdio.h>int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);//初始化int pthread_mutex_lock(pthread_mutex_t *mutex);//加锁int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁int pthread_mutex_destroy(pthread_mutex_t *mutex);//销毁锁
用互斥锁解决上面问题:
代码实现:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <assert.h>#include <pthread.h>pthread_mutex_t mutex;char buff[128]={0};void *fun(void *arg){ while(1) { pthread_mutex_lock(&mutex); int i=0; int count=0; for(;i<strlen(buff);++i) { if(isalpha(buff[i]) && !isalpha(buff[i+1])) { count++; } } printf("count == %d\n",count); pthread_mutex_unlock(&mutex); sleep(1); }}void main(){ pthread_mutex_init(&mutex,NULL); pthread_t id; int res=pthread_create(&id,NULL,fun,NULL); assert(res==0); while(1) { pthread_mutex_lock(&mutex); printf("Input: \n"); fflush(stdout); fgets(buff,128,stdin); buff[strlen(buff)-1]=0; if(strncmp(buff,"end",3)==0) { break; } pthread_mutex_unlock(&mutex); sleep(1); }}
(2)信号量
信号量的基本函数:
#include<semaphore.h>int sem_init(sem_t *sem,int pshared,unisigned int value);//初始化int sem_wait(sem_t *sem);//相当于进程中的P操作int sem_post(sem_t *sem);//相当于进程中的V操作int sem_destroy(sem_t *sem);//用完信号良好对它进行清理
针对上面用互斥锁解决的问题,用信号量解决,代码如下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <assert.h>#include <pthread.h>#include <semaphore.h>sem_t sem;char buff[128]={0};void *fun(void *arg){ while(1) { sem_wait(&sem); int i=0; int count=0; for(;i<strlen(buff);++i) { if(isalpha(buff[i]) && !isalpha(buff[i+1])) { count++; } } printf("count == %d\n",count); }}void main(){ sem_init(&sem,0,0); pthread_t id; int res=pthread_create(&id,NULL,fun,NULL); assert(res==0); while(1) { printf("Input: \n"); fflush(stdout); fgets(buff,128,stdin); buff[strlen(buff)-1]=0; if(strncmp(buff,"end",3)==0) { break; } sem_post(&sem); }}
(3)条件变量
在系统死锁中有这么一个典型的实例:
在一条生产线上有一个仓库,当生产者生产的时候需要锁住仓库独占,而消费者取产品的时候也要锁住仓库独占。如果生产者发现仓库满了,那么他就不能生产了,变成了阻塞状态。但是此时由于生产者独占仓库,消费者又无法进入仓库去消耗产品,这样就造成了一个僵死状态。
我们需要一种机制,当互斥量被锁住以后发现当前线程还是无法完成自己的操作,那么它应该释放互斥量,让其他线程工作。
A、可以采用轮询的方式,不停的查询你需要的条件
B、让系统来帮你查询条件,使用条件变量pthread_cond_t cond
条件变量使用之前需要初始化
a、pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
b、int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);//默认属性为空NULL
条件变量使用完成之后需要销毁
int pthread_cond_destroy(pthread_cond_t *cond);
条件变量使用需要配合互斥量
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
a、使用pthread_cond_wait等待条件变为真。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传递给函数。
b、这个函数将线程放到等待条件的线程列表上,然后对互斥量进行解锁,这是个原子操作。当条件满足时这个函数返回,返回以后继续对互斥量加锁。
int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);
c、这个函数与pthread_cond_wait类似,只是多一个timeout,如果到了指定的时间条件还不满足,那么就返回。时间用下面的结构体表示
struct timespec{
time_t tv_sec;
long tv_nsec;
};
注意,这个时间是绝对时间。例如你要等待3分钟,就要把当前时间加上3分钟然后转换到 timespec,而不是直接将3分钟转换到 timespec
当条件满足的时候,需要唤醒等待条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
a、pthread_cond_broadcast唤醒等待条件的所有线程
b、pthread_cond_signal至少唤醒等待条件的某一个线程
注意,一定要在条件改变以后在唤醒线程
简单来说:同步需要等待,异步不需要等待。
注:后面关于条件变量的总结是转载别人的,因为觉得有用,而且总结得很好。
- 线程同步的方法—互斥锁、信号量和条件变量
- 线程同步—条件变量和信号量
- 线程间同步--互斥锁、条件变量、信号量
- 线程间同步--互斥锁、条件变量、信号量
- 线程的同步控制---信号量、互斥锁、条件变量
- 线程同步的方式——Mutex(互斥量)、 Condition variable(条件变量)和Semaphore(信号量)
- 线程控制[pthread_create() pthread_join()] 线程同步[互斥锁 条件变量 信号量]
- 线程控制[pthread_create() pthread_join()] 线程同步[互斥锁 条件变量 信号量]
- Linux线程同步(条件变量和信号量)
- 线程的同步与互斥:条件变量&信号量
- 线程同步(互斥锁、读写锁、条件变量、信号量)
- 线程同步(信号量,互斥,条件变量)
- (四十三)线程——线程同步(互斥锁、读写锁、条件变量、信号量)
- 互斥锁,条件变量和信号量的区别
- 线程同步、条件变量、互斥锁的使用
- 线程同步、条件变量、互斥锁的使用
- 线程同步之信号量,代码实现方法2(条件变量+mutex互斥量)
- 多线程同步(信号量,互斥锁,条件变量)
- SSH无法连接虚拟机CentOS6.5主机
- java用jedis连接redis碰到的问题
- ashx 获取post数据的方式
- 用form表单向后端传file的时候,后端接收不到
- 线程控制实现彩色线条绘制
- 线程同步的方法—互斥锁、信号量和条件变量
- [AHK]想知道如何判断数字小键盘是否开启?
- Intel VTune Amplifier XE 使用
- js拼接字符串函数名称中带参数引号问题
- 最大公因数(gcd)
- Hadoop YARN配置参数剖析(2)—权限与日志聚集相关参数
- LintCode 房屋染色II
- 绝不止20大改变 iOS11对比iOS10
- 应用Wireshark IO图形工具分析数据流