linux 线程同步(二)
来源:互联网 发布:用户行为数据挖掘 编辑:程序博客网 时间:2024/04/29 19:32
信号量
信号量是互斥锁的升级版把互斥锁中1变成了n,举个简单的例子:假设现在有10个人,有一部手机,这10个人都竞争来使用手机打电话这就是互斥锁。对于信号量,现在可能是有4部手机,这10个人都竞争来使用手机打电话。相比互斥锁信号量由1变成了4。信号量相也就是操作系统中pv操作,它广泛应用进程或者线程间的同步与互斥。
相关库函数介绍
#include <semaphore.h>//所需头文件//初始化信号量sem初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享value表示要信号量初始值,pshared表示是否再多进程之前共享。0表示不在多进程间共享,非0表示在多进程之间共享具体可以man sem_init//成功返回0,出错返回-1int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_wait(sem_t *sem)//相当于p操作int sem_try_wait(sem_t *sem)//相当于p操作,在信号量值大于0时都能将信号量的值减一,与上面sem_wait的区别是,在信号值小于0时int sem_post(sem_t *sem)//相当于v操作int sem_getvalue(sem_t *sem)//用于得到信号量的值int sem_destory(sem_t *sem) //释放信号量
信号量实例:生产者消费值
#include<stdio.h>#include<stdlib.h>#include <pthread.h>#include <semaphore.h>#define BUFSIZE 10int buf[BUFSIZE];sem_t consumer_sem,producer_sem;void *consumer(void *arg){int c=0;while(1){sem_wait(&consumer_sem);//开始消费consumer_sem值减一printf("consumer %d: %d\n",c,buf[c]);//消费数据c++;c=c%BUFSIZE; sleep(1);//睡眠1ssem_post(&producer_sem);//producer_sem值加1}}void *producer(void *arg){int p=0;while(1){sem_wait(&producer_sem);//开始生产producer_sem值减一buf[p]=rand() % 1000 + 1;//生产数据printf("producer %d: %d\n",p,buf[p]);p++;p=p%BUFSIZE;sem_post(&consumer_sem);//consumer_sem值加1}}int main(){sem_init(&consumer_sem,0,0);sem_init(&producer_sem,0,BUFSIZE);pthread_t pid,cid;pthread_create(&pid,NULL,producer,NULL);pthread_create(&cid,NULL,consumer,NULL);pthread_join(pid, NULL);pthread_join(cid, NULL);sem_destroy(&consumer_sem);sem_destroy(&producer_sem);return 0;}
条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
条件变量类型为 pthread_cond_t。
相关库函数简介
#include<pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);//条件变量的资源释放int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);//条件变量的初始化
#include<pthread.h>int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *mutex,const struct timespec *abstime);int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);//等待某个条件是否成立。对于timewait()函数除了等待以外,可以设置一个时长。 int pthread_cond_signal(pthread_cond_t *cond);//种情况是只有一个线程收到后执行动作。//活动线程只需要唤醒第一个正在睡眠的线程。假设您只对队列添加了一个工作作业。那么只需要唤醒一个工作程序线程(再唤醒其它线程是不礼貌的!)int pthread_cond_broadcast(pthread_cond_t *cond);//通过广播的形式发给子线程消息,子线程竞争执行。
无论哪种等待方式,都必须和互斥锁结合,以防止多个线程同时请求pthread_cond_wait()(或pthread_cond_timedwait())的竞争条件,且在调用pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入pthread_cond_wait()前的加锁动作对应。
#include <stdlib.h>#include <pthread.h>#include <stdio.h>#include <unistd.h>struct msg { struct msg *next; int num;};struct msg *head;/* 条件变量 */pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;void *consumer(void *p){ struct msg *mp; while(1){ pthread_mutex_lock(&lock); /* pthread_cond_wait(&has_product, &lock); * 1.阻塞等待has_product被唤醒, * 2.释放互斥锁, pthread_mutex_unlock(&lock) * 3.当被唤醒时,解除阻塞,并且重新去申请获得互斥锁 pthread_mutex_lock(&lock) */ while (head == NULL) pthread_cond_wait(&has_product, &lock);//等待 mp = head; head = mp->next; pthread_mutex_unlock(&lock); printf("Consume %d\n", mp->num); free(mp); sleep(rand() % 5); }}void *producer(void *p){ struct msg *mp; while(1){ mp =(struct msg *)malloc(sizeof(struct msg)); mp->num = rand() % 1000 + 1; printf("Produce %d\n", mp->num); pthread_mutex_lock(&lock); mp->next = head; head = mp; pthread_mutex_unlock(&lock); /* pthread_cond_broadcast(&has_product) 唤醒等待队列上的所有线程*///发送信号,告诉消费者有产品了 pthread_cond_signal(&has_product); sleep(rand() % 5); }}int main(int argc, char *argv[]){ pthread_t pid, cid; srand(time(NULL)); pthread_create(&pid, NULL, producer, NULL); pthread_create(&cid, NULL, consumer, NULL); pthread_join(pid, NULL); pthread_join(cid, NULL); return 0;}
0 0
- linux 线程同步(二)
- 线程(二)-线程同步
- Linux C 线程同步实例分析(二)
- Linux C 多线程互斥锁及线程同步问题 (二)
- Linux多线程编程(二)线程同步之条件变量
- Linux线程同步(二)之使用信号量
- JAVA线程同步(二)
- (二)线程同步基础
- Java线程同步(二)
- 多线程(二)--线程同步
- [GNU/Linux] Linux系统调用-线程相关(二):线程同步
- Python线程编程(二)线程同步
- QT线程(二)---线程同步
- java线程(二)线程同步问题
- QT线程(二)---线程同步
- QT线程(二)---线程同步
- C#中的线程(二)线程同步
- C#中的线程(二)线程同步
- Spring中如何向 Bean注入系统属性或环境变量
- linux新建用户和用户组
- 铅
- Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
- 类的内存偏移
- linux 线程同步(二)
- 畅通工程续
- 言语不能表达千万分之一
- 曾经的笔记迁移__数组
- poj-3009 Curling 2.0-DFS
- 数据存储值归档Archive
- Video size 视频尺寸和名称
- FZU2129 子序列个数 DP
- StringUtils.isEmpty和StringUtils.isBlank用法