Liunx线程的同步
来源:互联网 发布:mac的usb不支持 编辑:程序博客网 时间:2024/05/22 03:11
什么是线程间的同步:
对于可以处理同一公共资源的线程来说他们必须是互斥的,这样才能保证数据的正确性。可是就这一种关系仍然不能处理好这些线程之间的问题。
比如,两个线程可以访问同一块缓冲区,线程1可以往里面写数据,线程2可以从中读数据,要是数据远远大于缓冲区的大小时,这时当线程1写满缓冲区时,就不能在写入了,必须等到线程2去读掉缓冲区的数据之后才能在写入。所以最好的做法就是在线程1写满时,去通知线程2要去读缓冲区的数据了,这就是线程之间的同步。
可以发现,线程间同步的基础是线程之间是互斥的,要是线程之间没有互斥关系也就谈不上同步了。
要了解现线程之间的同步关系,我们以简单的生产者消费者模型进行讨论。
对生产者和消费者的关系进行分析:
生产者与生产者:互斥关系,同时只有一个生产者可以生产数据,不然会发生数据的异常。
生产者与消费者:互斥与同步关系,生产者生产时消费者不能去读取数据,不然会发生数据异常;当生产者将缓冲区生产满时或者其他条件必须让消费者读取时,需要通知消费者去读取数据。
消费者与消费者:互斥关系,对于一个数据,只能被一个消费者所读取。
在此我们以一个生产者与一个消费者为例。
同步机制的实现条件:
①互斥是同步的基础,所以要实现同步必须先实现线程间的互斥。
②引入条件变量,条件变量是一种数据,用来描述资源就绪与否的状态,它与互斥机制结合使用就可实现同步机制。
条件变量的操作:
①条件变量的初始化:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
参数描述:
cond:要初始化的条件变量,是一个pthread_cond_t类型的变量。
attr:条件变量的状态,初始化时默认为NULL
返回值:
成功返回0,失败返回错误码
②条件变量的销毁
int pthread_cond_destroy(pthread_cond_t *cond);
参数描述
cond:要销毁的条件变量。
返回值:
成功返回0,失败返回错误码。
③条件变量的等待
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
函数说明:在条件不满足时会被挂起到等待队列,此时线程会释放掉锁资源,在线程被唤醒退出等待队列时,会重新获得锁资源。
参数描述:
cond:条件变量
mutex:互斥锁
④条件变量的唤醒
int pthread_cond_signal(pthread_cond_t *cond);
函数说明:在一个线程需要唤醒另一个等待的线程时使用,cond是这两个线程共同使用的条件变量。
参数说明:
cond:标识那个条件变量
返回值:
成功返回0,失败返回错误码。
int pthread_cond_broadcast(pthread_cond_t *cond);
函数说明:与上面的函数类似,不过上面的是激活一个线程,这个是激活所有等待的线程
【生产者与消费者模型】
缓冲区是一个单链表,生产者生成结点插入到单链表的头部,消费者从单链表的头部拿到结点。规定生产者每次生产一个结点消费者就去拿到这个结点。
分析:
①在单链表为空时,消费者不能去拿结点,需要等待生产者生产结点。
②在生产者生产时,消费者不能去拿结点。
③当生产者生产完成一个结点后需要告诉消费者可以拿结点了,这就需要使用条件变量。
④消费者拿结点时,生产者不能生产结点。这就需要互斥锁用来实现它们之间的互斥。
代码实现:
#include<stdio.h>#include<pthread.h>#include<stdlib.h>typedef struct Node{ int value; struct Node* next;}Node;Node* alloc(int value){ Node* pTmp = (Node*) malloc(sizeof(Node)); pTmp->value = value; pTmp->next = NULL; return pTmp;}void Free(Node* pTmp){ if(pTmp) free(pTmp); pTmp = NULL;}void InitList(Node** pHead){ *pHead = (Node*) malloc(sizeof(Node)); (*pHead)->next = NULL;}void PushFront(Node* pHead, int value){ Node* pTmp = alloc(value); pTmp->next = pHead->next; pHead->next = pTmp;}void PopFront(Node* pHead){ Node* pTmp = pHead->next; if(pTmp) { pHead->next = pTmp->next; Free(pTmp); }}void DestroyList(Node** pHead){ while((*pHead)->next) { PopFront(*pHead); } Free(*pHead);}void PrintList(Node* pHead){ while(pHead->next) { printf("%d ", pHead->next->value); pHead = pHead->next; } printf("\n");}int isEmpty(Node* pHead){ if(pHead->next) return 0; return 1;} int SizeList(Node* pHead){ int count = 0; pHead = pHead->next; while(pHead) { count++; pHead = pHead->next; } return count;}//创建链表Node* pHead;//创建条件变量pthread_cond_t need_prod = PTHREAD_COND_INITIALIZER;//创建互斥锁pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//生产者void *product(void *arg){ while(1){ sleep(1); //申请锁 pthread_mutex_lock(&lock); int data = rand() % 123; PushFront(pHead, data); printf("生产者生产完成: %d\n", data); //释放锁 pthread_mutex_unlock(&lock); //唤醒消费者线程 pthread_cond_signal(&need_prod); }}//消费者void *consumer(void *arg){ while(1){ //申请锁 pthread_mutex_lock(&lock); while(isEmpty(pHead)) { printf("生产者没有生产完毕,消费者等待\n"); //如果链表中为空,消费者就要进行等待,等生产者生产完成后唤醒自己 //在进入等待队列时,它会释放锁资源,以便其他进程进行生产,在出等待队列时,它会恢复锁的状态 pthread_cond_wait(&need_prod, &lock); } printf("消费者消费完毕: %d\n", pHead->next->value); PopFront(pHead); //释放锁 pthread_mutex_unlock(&lock); }}int main(){ InitList(&pHead); pthread_t thread1; pthread_t thread2; pthread_create(&thread1, NULL, product, NULL); pthread_create(&thread2, NULL, consumer, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); //销毁互斥锁 pthread_mutex_destroy(&lock); //销毁条件变量 pthread_cond_destroy(&need_prod); DestroyList(&pHead); return 0;}
运行结果:
阅读全文
0 0
- Liunx线程的同步
- liunx查看线程的方法
- 关于线程死锁的了解(LIUNX)
- liunx时钟与同步
- liunx多线程 同步
- 线程的同步-同步方法
- 线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Java线程:线程的同步-同步方法
- Java线程:线程的同步-同步块
- Windows中的时间(SYSTEMTIME和FILETIME)
- 面试题26复杂连标的复制
- Android应用自定义View绘制方法手册
- python入门(@property,@*.setter)
- 获取iOS任意线程调用堆栈(四)符号化实战
- Liunx线程的同步
- Java做题笔记
- MySQL时间函数
- Ember旅程系列(二)-- 设计的你应用
- Python爬虫:抓取新浪新闻数据
- PLS-00642: local collection types not allowed in SQL statements
- springMVC+mybatis分页
- 课程设计--图书信息管理系统(C语言)
- 如何在linux服务器中配置ssh互信(不需要密码即可ssh登陆)