linux线程学习(4)

来源:互联网 发布:java报表打印 编辑:程序博客网 时间:2024/06/05 11:57

线程的同步

1. 条件变量
提供线程之间的一种通知机制,当某一条件满足时,线程A可以通知阻塞在条件变量上的线程B,B所期望的条件已经满足,可以解除在条件变量上的阻塞操作,继续做其他事情。
我们需要这种机制,当互斥量被锁住以后发现当前线程还是无法完成自己的操作,那么它应该释放互斥量,让其他线程工作。
1、可以采用轮询的方式,不停的查询你需要的条件
2、让系统来帮你查询条件,使用条件变量pthread_cond_t cond

2. 条件变量的初始化和销毁

//条件变量使用之前需要初始化pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int pthread_cond_init(pthread_cond_t *restrict cond,             const pthread_condattr_t *restrict attr);        // 默认属性为空NULL//条件变量使用完成之后需要销毁int pthread_cond_destroy(pthread_cond_t *cond);

3. 条件变量的使用

//条件变量使用需要配合互斥量int pthread_cond_wait(pthread_cond_t *restrict cond,         pthread_mutex_t *restrict mutex);//1、使用pthread_cond_wait等待条件变为真。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传递给函数。//2、这个函数将线程放到等待条件的线程列表上,然后对互斥量进行解锁,这是个原子操作。当条件满足时这个函数返回,返回以后继续对互斥量加锁。

当条件满足的时候,需要唤醒等待条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
1、pthread_cond_broadcast唤醒等待条件的所有线程
2、pthread_cond_signal至少唤醒等待条件的某一个线程
注意,一定要在条件改变以后在唤醒线程

4. 实例练习
创建两个线程,一个线程往buff里写数据,每隔1s写一次,总共写30次,一个线程往buff里读数据,每隔2s读一次,总共读30次:

#include <pthread.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <errno.h>#define BUFF_SIZE  5typedef struct product{       int buff[BUFF_SIZE];//数据buff    int readpos,writepos;//读写位置,即buff的下标    pthread_mutex_t lock;//互斥量,配合条件变量使用    pthread_cond_t notempty;//非空条件    pthread_cond_t notfull;//非满条件}*Buff_t;void put(Buff_t p,int data);int get(Buff_t p);//进行互斥量、条件变量、位置(下标)的初始化void init_func(Buff_t p){    pthread_mutex_init(&(p->lock),NULL);//互斥量初始化    //条件变量初试化    pthread_cond_init(&(p->notempty),NULL);    pthread_cond_init(&(p->notfull),NULL);    //初始化时读和写的位置(下标)均为零    p->readpos=0;    p->writepos=0;}//函数功能:进行互斥量、条件变量的销毁void destory(Buff_t p){    pthread_mutex_destroy(&p->lock);    pthread_cond_destroy(&p->notempty);    pthread_cond_destroy(&p->notfull);    p->readpos=0;    p->writepos=0;}void * producer(void *arg)//子线程生成,然后放入buff{    int i;    for(i=1;i<=30;i++)    {        put((Buff_t)arg,i);        printf("put the %d production to buff\n",i);        sleep(1);        printf("put the %d production to buff success\n",i);    }    return NULL;}void *customer(void *arg)//子线程消费,行buff去出相关值并打印{    int i,val;    for(i=1;i<=30;i++)    {        val=get((Buff_t)arg);        printf("get the production form buff\n");        sleep(2);        printf("get the production form buff success,val is %d\n",val);    }    return NULL;}void put(Buff_t p,int data){    pthread_mutex_lock(&p->lock);//进行加锁操作    if((p->writepos+1)%BUFF_SIZE == p->readpos)//判断buff是否满了    {        printf("producer wait for not full\n");        pthread_cond_wait(&p->notfull, &p->lock);//如果满了,就需要等待到非满的时候,等待时,互斥量会被解锁,其他有进行加锁的线程就可以运行(这里的等待时,get()函数就可运行),当条件满足时这个函数返回,返回以后继续对互斥量加锁。    }    p->buff[p->writepos] = data;//buff非满时,就可往buff里写入数据,    p->writepos = (p->writepos+1) % BUFF_SIZE;//写位置加一,当超过BUFF_SIZE时,要从头开始(即为零)    pthread_cond_signal(&p->notempty);//发出非空信号,唤醒等待条件的线程    pthread_mutex_unlock(&p->lock);//解锁操作}int get(Buff_t p){       int val;    pthread_mutex_lock(&p->lock);//进行加锁操作    if(p->readpos==p->writepos)//判断buff是否为空,为空就等待,直到为非空    {        printf("it is empty,wait\n");        pthread_cond_wait(&p->notempty,&p->lock);    }    val = p->buff[p->readpos];    p->readpos=(p->readpos+1)%BUFF_SIZE;     pthread_cond_signal(&p->notfull);    pthread_mutex_unlock(&p->lock);    return val;}int main(){    Buff_t p=(Buff_t)malloc(sizeof(struct product));    pthread_t product_t,customer_t;//线程id    init_func(p); //在使用互斥量、条件变量前,调用初始化函数,进行相关初始化    //创建两个线程,线程producer往buff中每秒存值一次,存30次    //线程customer从buff中每两秒取值一次,并打印,取30次    pthread_create(&product_t, NULL, producer, (void *)p);      pthread_create(&customer_t, NULL, customer, (void *)p);      //连接线程,等待线程结束    pthread_join(product_t, NULL);      pthread_join(customer_t, NULL);      //销毁互斥量、条件变量    destory(p);    return 0;}

运行结果:
这里写图片描述

原创粉丝点击