线程同步(条件变量)

线程同步(条件变量)

条件变量是线程的另一种同步机制。
条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
条件本身是由互斥量保护的。线程在改变条件状态之前必须首先锁住互斥量。其他线程在获得互斥量之前不会察觉到这种改变,因为互斥量必须在锁定以后才能计算条件。

使用条件变量前,必须先对它进行初始化。条件变量的数据类型为pthread_cond_t。它有两种初始化方式:
1、直接把常量PTHREAD_COND_INITIALIZER赋值给静态分配的条件变量。
2、如果条件变量是动态分配的,需要使用pthread_cond_init函数对它进行初始化。

在释放条件变量底层的内存空间前,可以使用pthread_cond_destroy函数对条件变量进行销毁。
注意:不能用多个线程初始化同一个条件变量,当一个线程要使用条件变量的时候确保它是未被使用的。

#include <pthread. h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
//两个函数的返回值:若成功,返回0;否则,返回错误编码

除非需要创建一个具有非默认属性的条件变量,否则pthread_cond_init函数的attr参数可以设置为 NULL。

我们使用pthread_cond_wait等待条件变量变为真。如果在给定的时间内条件不能满足,那么会生成一个返回错误码的变量。


#include <pthread. h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr);
//两个函数的返回值:若成功,返回0;否则,返回错误编码

传递给pthread_cond_wait的互斥量对条件进行保护。调用者把锁住的互斥量传给函数,函数然后自动把调用线程放到等待条件的线程列表上,对互斥量解锁。
这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。
pthread_cond_timedwait函数的功能与pthread_cond_wait函数相似,只是多了一个超时( tsptr)。超时值指定了我们愿意等待多长时间,它是通过timespec结构指定的。

使用方式:

使用pthread_cond_wait方式如下:

pthread _mutex_lock(&mutex)
while或if(线程执行的条件是否成立)
pthread_cond_wait(&cond, &mutex);
/* 线程执行语句 */
pthread_mutex_unlock(&mutex);

这里在调用pthread_cond_wait前需要互斥量进行加锁的原因是:确保在公有资源条件状态改变时,等待条件的线程已经被放到等待条件的线程列表上。

使用while和if判断线程执行条件是否成立的区别:
一般来说,在多线程资源竞争的时候,在一个使用资源的线程里面(消费者)判断资源是否可用,不可用便调用pthread_cond_wait,在另一个线程里面(生产者)如果判断资源可用的话,则调用pthread_cond_signal发送一个资源可用信号,这时候pthread_cond_wait就会返回,并且会再自动对互斥量进行加锁,然后线程接着执行下去。

下面是流程:

等待线程:

pthread_cond_wait前要先加锁
pthread_cond_wait内部会解锁,然后等待条件变量被其它线程激活
pthread_cond_wait被激活后会再自动加锁

激活线程:


加锁(和等待线程用同一个锁)
pthread_cond_signal发送信号(阶跃信号前最好判断有无等待线程)
解锁

激活线程的三个操作执行时,等待线程都处于pthread_cond_wait中,等待pthread_cond_signal发送信号激活。


实例:

#include <pthread.h>

struct msge {
    struct msge *m_next;
    /* ... more stuff here ...*/
};

struct msge *workq;

pthread_cond_t qready = PTHREAD_COND_INITIALIZER;

pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;

//等待条件(消费者)线程1
void process_msg(void){
    struct msge *mp;
    for (;;) {
        pthread_mutex_lock(&qlock);
        while (workq == NULL) {
            /*
            1、等待条件满足
            2、对互斥量进行解锁
            */
            //调用pthread_cond_signal通知条件满足时返回,返回后再次对互斥量加锁
            pthread_cond_wait(&qready, &qlock);
        }
    mp = workq;
    workq = mp->m_next;
    pthread_mutex_unlock(&qlock);
    /* now process the message mp */
    }
}


//产生条件(生产者)线程2
void enqueue_msg(struct msge *mp){
    pthread_mutex_lock(&qlock);
    mp->m_next = workq;
    workq = mp;
    pthread_mutex_unlock(&qlock);
    pthread_cond_signal(&qready);
}

这里用两个线程分别模拟生产者与消费者,消费者线程等待生产者线程产生特定的条件,然后再往下执行,这里因为是两个线程,所以生产者如果先于消费者获得互斥量并调用了pthread_cond_signal,消费者因为还没有进入等待条件状态,所以生产者发送的信号,消费者会忽略掉。

本书全面介绍了UNIX系统的程序设计界面—系统调用界面和标准C库提供的许多函数。 本书的前15章着重于理论知识的阐述,主要内容包括UNIX文件和目录、进程环境、进程控制、 进程间通信以及各种I/O。在此基础上,分别按章介绍了多个应用实例,包括如何创建数据库函数库, PostScript 打印机驱动程序,调制解调器拨号器及在伪终端上运行其他程序的程序等。 本书内容丰富权威, 概念清晰精辟,一直以来被誉为UNIX编程的“圣经”,对于所有UNIX程序员—无论是初学者还是专家级人士 —都是一本无价的参考书籍。 目 录 译者序 译者简介 前言 第1章 UNIX基础知识 1 1.1 引言 1 1.2 登录 1 1.2.1 登录名 1 1.2.2 shell 1 1.3 文件和目录 2 1.3.1 文件系统 2 1.3.2 文件名 2 1.3.3 路径名 2 1.3.4 工作目录 4 1.3.5 起始目录 4 1.4 输入和输出 5 1.4.1 文件描述符 5 1.4.2 标准输入、标准输出和标准 出错 5 1.4.3 不用缓存的I/O 5 1.4.4 标准I/O 6 1.5 程序和进程 7 1.5.1 程序 7 1.5.2 进程和进程ID 7 1.5.3 进程控制 7 1.6 ANSI C 9 1.6.1 函数原型 9 1.6.2 类属指针 9 1.6.3 原始系统数据类型 10 1.7 出错处理 10 1.8 用户标识 11 1.8.1 用户ID 11 1.8.2 组ID 12 1.8.3 添加组ID 12 1.9 信号 12 1.10 UNIX间值 14 1.11 系统调用和库函数 14 1.12 小结 16 习题 16 第2章 UNIX标准化及实现 17 2.1 引言 17 2.2 UNIX标准化 17 2.2.1 ANSI C 17 2.2.2 IEEE POSIX 18 2.2.3 X/Open XPG3 19 2.2.4 FIPS 19 2.3 UNIX实现 19 2.3.1 SVR4 20 2.3.2 4.3+BSD 20 2.4 标准和实现的关系 21 2.5 限制 21 2.5.1 ANSI C限制 22 2.5.2 POSIX限制 22 2.5.3 XPG3限制 24 2.5.4 sysconf、pathconf 和fpathconf 函数 24 2.5.5 FIPS 151-1要求 28 2.5.6 限制总结 28 2.5.7 未确定的运行间限制 29 2.6 功能测试宏 32 2.7 基本系统数据类型 32 2.8 标准之间的冲突 33 2.9 小结 34 习题 34 第3章 文件I/O 35 3.1 引言 35 3.2 文件描述符 35 3.3 open函数 35 3.4 creat函数 37 3.5 close函数 37 3.6 lseek函数 38 3.7 read函数 40 3.8 write函数 41 3.9 I/O的效率 41 3.10 文件共享 42 3.11 原子操作 45 3.11.1 添加至一个文件 45 3.11.2 创建一个文件 45 3.12 dup和dup2函数 46 3.13 fcntl函数 47 3.14 ioctl函数 50 3.15 /dev/fd 51 3.16 小结 52 习题 52 第4章 文件和目录 54 4.1 引言 54 4.2 stat, fstat和lstat函数 54 4.3 文件类型 55 4.4 设置-用户-ID和设置-组-ID 57 4.5 文件存取许可权 58 4.6 新文件和目录的所有权 60 4.7 access函数 60 4.8 umask函数 62 4.9 chmod和fchmod函数 63 4.10 粘住位 65 4.11 chown, fchown和 lchown函数 66 4.12 文件长度 67 4.13 文件截短 68 4.14 文件系统 69 4.15 link, unlink, remove和rename 函数 71 4.16 符号连接 73 4.17 symlink 和readlink函数 76 4.18 文件的间 76 4.19 utime函数 78 4.20 mkdir和rmdir函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值