linux线程学习(4)

线程的同步

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  5

typedef 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;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值