条件变量

2020-08-26  本文已影响0人  写一行代码

头文件:#include <pthread.h>

与互斥锁不同,条件变量是用来等待而不是用来上锁的,条件变量本身不是锁!
条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。
条件变量的两个动作:
条件不满, 阻塞线程
当条件满足, 通知阻塞的线程开始工作

pthread_cond_init

int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
功能:
初始化一个条件变量
参数:
cond:指向要初始化的条件变量指针。
attr:条件变量属性,通常为默认值,传NULL即可
也可以使用静态初始化的方法,初始化条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:
成功:0
失败:非0错误号

pthread_cond_destroy

int pthread_cond_destroy(pthread_cond_t *cond);
功能:
销毁一个条件变量
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号

pthread_cond_wait

int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
功能:
阻塞等待一个条件变量
a) 阻塞等待条件变量cond(参1)满足
b) 释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
a) b) 两步为一个原子操作。
c) 当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);

参数:
cond:指向要初始化的条件变量指针
mutex:互斥锁

返回值:
成功:0
失败:非0错误号

pthread_cond_timedwait

int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
功能:
限时等待一个条件变量

参数:
cond:指向要初始化的条件变量指针
mutex:互斥锁
abstime:绝对时间

返回值:
成功:0
失败:非0错误号

abstime说明:

struct timespec {
time_t tv_sec; /* seconds / // 秒
long tv_nsec; /
nanosecondes*/ // 纳秒
}
time_t cur = time(NULL); //获取当前时间。
struct timespec t; //定义timespec 结构体变量t
t.tv_sec = cur + 1; // 定时1秒
pthread_cond_timedwait(&cond, &t);

pthread_cond_signal

int pthread_cond_signal(pthread_cond_t *cond);
功能:
唤醒至少一个阻塞在条件变量上的线程
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号

pthread_cond_broadcast

int pthread_cond_broadcast(pthread_cond_t *cond);
功能:
唤醒全部阻塞在条件变量上的线程
参数:
cond:指向要初始化的条件变量指针
返回值:
成功:0
失败:非0错误号

生产者消费者程序

typedef struct node
{
    int data;
    struct node* next;
}Node;
​
Node* head = NULL;
​
pthread_mutex_t mutex;
pthread_cond_t cond;
​
void* producer(void* arg)
{
    while (1)
    {
        Node* pnew = (Node*)malloc(sizeof(Node));
        pnew->data = rand() % 1000; // 0-999

        pthread_mutex_lock(&mutex);
        pnew->next = head;
        head = pnew;
        printf("====== produce: %lu, %d\n", pthread_self(), pnew->data);
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond);
​
        sleep(rand() % 3);
    }
    return NULL;
}
​
void* customer(void* arg)
{
    while (1)
    {
        pthread_mutex_lock(&mutex);
        if (head == NULL)
        {
            // 该函数会对互斥锁解锁
            pthread_cond_wait(&cond, &mutex);
            // 解除阻塞之后,对互斥锁做加锁操作
        }
        // 链表不为空  - 删除头结点
        Node* pdel = head;
        head = head->next;
        printf("------ customer: %lu, %d\n", pthread_self(), pdel->data);
        free(pdel);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
​
int main(int argc, const char* argv[])
{
    pthread_t p1, p2;

    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
​
    pthread_create(&p1, NULL, producer, NULL);
    pthread_create(&p2, NULL, customer, NULL);
​
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);
​
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
​
    return 0;
}

​##条件变量的优缺点
相较于mutex而言,条件变量可以减少竞争。
如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果链表中没有数据,消费者之间竞争互斥锁是无意义的。
有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。

上一篇下一篇

猜你喜欢

热点阅读