linux 线程同步(二)
信号量
信号量是相互排斥锁的升级版把相互排斥锁中1变成了n。举个简单的样例:如果如今有10个人,有一部手机。这10个人都竞争来使用手机打电话这就是相互排斥锁。对于信号量,如今可能是有4部手机,这10个人都竞争来使用手机打电话。相比相互排斥锁信号量由1变成了4。信号量相也就是操作系统中pv操作,它广泛应用进程或者线程间的同步与相互排斥。
相关库函数介绍
#include <semaphore.h>//所需头文件
//初始化信号量sem初始化的时候能够指定信号量的初始值,以及能否够在多进程间共享value表示要信号量初始值,pshared表示是否再多进程之前共享。 0表示不在多进程间
共享,非0表示在多进程之间共享详细能够man sem_init
//成功返回0,出错返回-1
int 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 10
int 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);//睡眠1s
sem_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; }
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包含两个动作:一个线程等待"条件变量的条件成立"而挂起;还有一个线程使"条件成立"(给出条件成立信号)。
为了防止竞争,条件变量的使用总是和一个相互排斥锁结合在一起。
条件变量类型为 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;
}
linux 线程同步(二)的更多相关文章
- 【转】 Linux 线程同步的三种方法
线程的最大特点是资源的共享性,但资源共享中的同步问题是多线程编程的难点.linux下提供了多种方式来处理线程同步,最常用的是互斥锁.条件变量和信号量. 一.互斥锁(mutex) 通过锁机制实现线程间的 ...
- linux线程同步(1)-互斥量
一.概述 互斥量是线程同步的一种机制,用来保护多线程的共享资源.同一时刻,只允许一个线程对临界区进行 ...
- Linux线程同步之读写锁(rwlock)
读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 和 ...
- linux线程(二)内存释放
linux线程有两种模式joinable和unjoinable. joinable线程:系统会保存线程资源(栈.ID.退出状态等)直到线程退出并且被其他线程join. unjoinable线程:系统会 ...
- Linux线程同步
1. 线程同步: 当多个控制线程共享相同的内存时,需要确保每个线程看到一致的数据视图.当某个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要对这些线程进行同步,以确保他们在访问变量 ...
- Linux 线程同步的三种方法(互斥锁、条件变量、信号量)
互斥锁 #include <cstdio> #include <cstdlib> #include <unistd.h> #include <pthread. ...
- Linux线程同步:条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- linux线程同步(5)-屏障
一.概述 barrier(屏障)与互斥量,读写锁,自旋锁不同,它不是用来保护临界区的.相反,它跟条 ...
- linux线程同步(3)-读写锁
一.概述 读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区, ...
随机推荐
- Lodash数组方法中文总结
LodashAPI总结 Lodash是一个特别特别好用的工具,感觉有了Lodash就没有解决不了的问题了~~~~ 使用初开始 官网 https://www.lodashjs.com/docs/4.17 ...
- MySQL操作数据库和表的基本语句(DDL)
1.创建数据库: CREATE DATABASE 数据库名; eg.CREATE DATABASE test_ddl;2.创建表 CREATE TABLE 表名(列名 数据类型 约束,...); eg ...
- NSFileHandle类
Objective-C使用NSFileHandle类对文件进行基本操作,IOS文件操作 NSFileHandle类中得方法可以对文件进行基本的读写,偏移量的操作.NSFileHandle基本步骤:1. ...
- “完美”解决微信小程序购物车抛物动画,在连续点击时出现计算错误问题,定时器停不下来。
最近做,微信点餐小程序,遇到添加商品时出现抛物动画,参考借鉴了这位大神的方法 https://www.cnblogs.com/greengage/p/7815842.html 但出现了一个问题,连续点 ...
- JS 水印图片合成实例页面
CSS代码: .clip { position: absolute; clip: rect(0 0 0 0); } HTML代码: <input type="file" id ...
- MySQL主主配置及并行复制搭建
思路: 两台机器互为主从. 机器1:192.168.1.160 机器2:192.168.1.164 修改两台机器的my.cnf文件,server-id,log-bin,auto-increment-i ...
- 零基础入门学习Python(25)--字典:当索引不好用时
知识点 字典属于映射类型. 列表,元祖,字符串等属于序列类型 创建及访问字典 #创建一个字典 >>> dict1 = {'李宁':'一切皆有可能','耐克':'Just do it' ...
- buf.slice()
buf.slice([start[, end]]) start {Number} 默认:0 end {Number} 默认:buffer.length 返回:{Buffer} 返回一个指向相同原始内存 ...
- Variational Auto-Encoders原理
目录 AE v.s. VAE Generative model VAE v.s. GAN AE v.s. VAE Generative model VAE v.s. GAN
- 字符串String对象构造方法的创建和直接赋值的区别
/* * 通过构造方法创建的字符串对象和直接赋值方式创建的字符串对象有什么区别呢? * 区别是:通过构造方法创建的字符串对象是在堆内存.通过赋值创建的字符串对象是在方法区的常量池 * * == * 基 ...