【linux系统编程】1、条件变量

116 阅读2分钟

「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。

条件变量

本身不是锁,通常结合锁一起使用

函数:
    pthread_cond_t
    pthread_cond_init //初始化条件变量
    pthread_cond_destroy // 销毁条件变量
    pthread_cond_wait // 线程等待(阻塞)
    pthread_cond_timedwait // 线程等待(设置等待时间)
    pthread_cond_signal // 唤醒(通知一个)
    pthread_cond_broadcast // 唤醒(通知所有)

初始化条件变量:
    静态初始化:
        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    动态初始化:
        pthread_cond_t cond;
        pthread_cond_init(&cond,NULL);

阻塞等待条件:
    pthread_cond_wait(&cond,&mutex);
    作用:
        (1)阻塞等待条件变量cond
        (2)释放已经掌握的互斥锁(相当于 pthread_mutex_unlock(&mutex))
        (3)当条件满足,函数返回时,解除阻塞并重新申请获取互斥锁,重新加锁信号量(相当于:pthread_mutex_lock(&mutex));

        (1)(2)为原子操作

条件变量的生产者消费者模型分析

生产者:
    1、生产数据
    2、加锁 : pthread_mutex_lock(&mutex);
    3、将数据放入共享区
    4、解锁:pthread_mutex_unlock(&mutex);
    5、通知阻塞在条件变量上的线程
        pthread_cond_signal(&cond) // 至少唤醒一个阻塞在条件变量上的线程
        pthread_cond_broadcast(&cond) // 唤醒所有阻塞在条件变量上的线程
    6、循环生产数据

消费者:
    1、创建所:pthread_mutex_t mutex;
    2、初始化:pthread_mutex_init(&mutex,NULL);
    3、加锁:pthread_mutex_lock(&mutex);
    4、等待条件满足:
        pthread_cond_wait(&cond,&mutex);
        (1)阻塞等待条件变量
        (2)解锁 pthread_mutex_unlock(&mutex);
                ...
        (3)加锁:pthread_mutex_lock(&mutex);
    5、访问共享数据
    6、解锁、释放条件变量。
    

代码案例

        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <string.h>
        #include <error.h>
        #include <pthread.h>

        pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;      // 初始化一个互斥量
        pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; // 初始化一个条件变量

        struct msg
        {
            int num;
            struct msg *next;
        };
        struct msg *head;

        void err_thread(int ret, char *str)
        {

            if (ret != 0)
            {
                fprintf(stderr, "%s:%s\n", str, strerror(ret));
                pthread_exit(NULL);
            }
        }

        // 生产者
        void *producer(void *arg)
        {
            struct msg *mp;
            while (1)
            {
                // 模拟生产一个数据
                mp = malloc(sizeof(struct msg));
                mp->num = rand() % 100 + 1;
                printf("--- producer %lu : produce a num = %d\n", pthread_self(), mp->num);

                // 加锁
                pthread_mutex_lock(&lock);
                // 访问共享数据
                mp->next = head;
                head = mp;
                // 解锁
                pthread_mutex_unlock(&lock);
                // 唤醒阻塞在条件变量 has_product 的线程
                pthread_cond_broadcast(&has_product);
                sleep(rand() % 5);
            }
        }

        // 消费者
        void *consumer(void *arg)
        {
            struct msg *mp;

            while (1)
            {
                // 加锁
                pthread_mutex_lock(&lock);
                // 等待条件满足
                while (head == NULL)
                {
                    pthread_cond_wait(&has_product, &lock);
                }

                // 访问共享数据
                mp = head;
                head = mp->next;
                // 解锁
                pthread_mutex_unlock(&lock);

                printf("--- consumer %lu : comsume a num = %d\n", pthread_self(), mp->num);
                free(mp);
                sleep(rand() % 5);
            }
        }

        int main()
        {
            pthread_t pid, cid;
            srand(time(NULL));
            // 两个生产者
            pthread_create(&pid, NULL, producer, NULL);
            pthread_create(&pid, NULL, producer, NULL);

            // 三个消费者
            pthread_create(&cid, NULL, consumer, NULL);
            pthread_create(&cid, NULL, consumer, NULL);
            pthread_create(&cid, NULL, consumer, NULL);

            pthread_join(pid, NULL);
            pthread_join(cid, NULL);

            return 0;
        }