线程同步---条件变量以及结合互斥锁构建生产者消费者模型

条件变量
什么是条件变量?
  • 条件变量是进行线程阻塞的一种机制,经常和互斥锁结合起来处理生产者消费者模型
  • 条件变量给多线程提供了一个会合的场所。条件变量与互斥锁一起使用时,允许线程以无竞争的方式等待特定的条件发生
  • 条件变量只有满足特定条件(如,任务队列已满或已空)时才会阻塞线程;如果条件不满足,多个线程可以同时进入临界区,同时读写共享资源,因此还是会造成共享资源的混乱;因此条件变量通常要和互斥锁一起使用,利用互斥锁保证线程同步。

条件变量相关的函数API

#include <pthread.h>
pthread_cond_t cond; // 被条件变量阻塞的线程的线程信息会被记录到这个变量中,以便在解除阻塞的时候使用
// 初始化
int pthread_cond_init(pthread_cond_t *restrict cond,
      const pthread_condattr_t *restrict attr);
// 销毁释放资源        
int pthread_cond_destroy(pthread_cond_t *cond);

// 线程阻塞函数, 哪个线程调用这个函数, 哪个线程就会被阻塞
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

// 表示的时间是从1971.1.1到某个时间点的时间, 总长度使用秒/纳秒表示
struct timespec {
	time_t tv_sec;      /* Seconds */
	long   tv_nsec;     /* Nanoseconds [0 .. 999999999] */
};
// 将线程阻塞一定的时间长度, 时间到达之后, 线程就解除阻塞了
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
           pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

// 唤醒阻塞在条件变量上的线程, 至少有一个被解除阻塞
int pthread_cond_signal(pthread_cond_t *cond);
// 唤醒阻塞在条件变量上的线程, 被阻塞的线程全部解除阻塞
int pthread_cond_broadcast(pthread_cond_t *cond);


链接: https://subingwen.cn/linux/thread-sync/#5-1-%E6%9D%A1%E4%BB%B6%E5%8F%98%E9%87%8F%E5%87%BD%E6%95%B0

生产者与消费者模型的源代码

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

#define QUEUEMAX 10 

// 互斥锁与条件变量
pthread_mutex_t mutex;
pthread_cond_t cons_cond;
pthread_cond_t prod_cond;

// 节点
typedef struct node
{
    int num;
    struct node* next;
}Node;

// 指向头结点的指针
Node* head = NULL;
int count = 0;

/* 节点插入方式如下所示
* head-->null
* newNode1
* head-->newNode1-->null
* newNode2
* head-->newNode2-->newNode1-->null
* .....
*/
void* producer(void* arg) {
    // 创建节点
    while (1) {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->num = rand() % 100;
        // 上锁
        pthread_mutex_lock(&mutex);

        // 假如队列已经满,阻塞生产者线程
        // 用while不能用if
        while (count >= 10) {
            pthread_cond_wait(&prod_cond, &mutex);  // 记得唤醒哦
        }

        newNode->next = head;
        head = newNode;
        count++;
        printf("+++Producer  id: %ld, number: %d, count: %d\n", pthread_self(), newNode->num, count);
        // 解锁
        pthread_mutex_unlock(&mutex);

        // 唤醒至少一个阻塞的消费者线程
        pthread_cond_signal(&cons_cond);    

        sleep((unsigned int)rand() % 2);
    }
    return NULL;
}

void* consumer(void* arg) {
    while (1) {
        // 上锁
        pthread_mutex_lock(&mutex);
        // 假如队列已空,应该让消费者线程阻塞
        while (head == NULL || count == 0) {
            pthread_cond_wait(&cons_cond, &mutex); // 要记得唤醒哦!
        }
        Node* curNode = head;
        count--;
        printf("---Consumer  id: %ld, number: %d, count: %d\n", pthread_self(), curNode->num, count);
        head = head->next;
        free(curNode);
        // 解锁
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&prod_cond);

        sleep((unsigned int)rand() % 3);
    }
    return NULL;
}

int main()
{
    // 初始化锁和条件变量
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cons_cond, NULL);

    // t1是生产者线程数组 t2是消费者线程数组
    pthread_t t1[5], t2[5];

    // 创建线程
    for (int i = 0; i < 5; i++) {
        pthread_create(&t1[i], NULL, producer, NULL);
    }
    for (int i = 0; i < 5; i++) {
        pthread_create(&t2[i], NULL, consumer, NULL);
    }

    // 回收线程
    for (int i = 0; i < 5; i++) {
        pthread_join(t1[i], NULL);
    }
    for (int i = 0; i < 5; i++) {
        pthread_join(t2[i], NULL);
    }

    // 销毁互斥锁和条件变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cons_cond);
    return 0;
}
参考文献:

①《程序员的自我修养》
② https://subingwen.cn/linux/thread-sync/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux中,可以使用C语言的条件变量和线程来实现消费者-生产者模型。下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define BUFFER_SIZE 10 int buffer[BUFFER_SIZE]; int count = 0; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_prod = PTHREAD_COND_INITIALIZER; pthread_cond_t cond_cons = PTHREAD_COND_INITIALIZER; void *producer(void *arg) { int item = 0; while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区已满,则等待消费者消费 while (count == BUFFER_SIZE) { pthread_cond_wait(&cond_prod, &mutex); } buffer[count] = item; count++; printf("Producer produced item %d\n", item); // 唤醒消费者线程 pthread_cond_signal(&cond_cons); pthread_mutex_unlock(&mutex); item++; } pthread_exit(NULL); } void *consumer(void *arg) { while (1) { pthread_mutex_lock(&mutex); // 如果缓冲区为空,则等待生产者生产 while (count == 0) { pthread_cond_wait(&cond_cons, &mutex); } int item = buffer[count - 1]; count--; printf("Consumer consumed item %d\n", item); // 唤醒生产者线程 pthread_cond_signal(&cond_prod); pthread_mutex_unlock(&mutex); } pthread_exit(NULL); } int main() { pthread_t producer_thread, consumer_thread; // 创建生产者和消费者线程 pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); // 等待线程结束 pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); return 0; } ``` 在上面的代码中,生产者线程不断地向缓冲区中生产数据,而消费者线程不断地从缓冲区中消费数据。当缓冲区满时,生产者线程会等待条件变量`cond_prod`,直到有消费者消费数据才会被唤醒。同样,当缓冲区为空时,消费者线程会等待条件变量`cond_cons`,直到有生产者生产数据才会被唤醒。 需要注意的是,在生产者和消费者线程之间共享的变量`count`和`buffer`需要进行互斥访问,因此使用了互斥锁`mutex`来保护共享资源的访问。 希望这个示例能帮助你理解如何在Linux中使用C语言的条件变量和线程实现消费者-生产者模型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡与乌龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值