条件变量线程抢锁与虚假唤醒

博客详细讨论了条件变量线程在被唤醒后抢锁的过程,以及多线程环境下可能存在的虚假唤醒问题。在被唤醒后,线程需要重新判断条件是否满足,以避免虚假唤醒。文中通过实例解释了pthread_cond_wait和pthread_cond_signal的交互,以及如何处理虚假唤醒的情况。
摘要由CSDN通过智能技术生成

目录

1,阻塞在条件变量上的线程被唤醒后需抢锁

2,多个阻塞在条件变量上的线程被唤醒时,会产生虚假唤醒


1,阻塞在条件变量上的线程被唤醒后需抢锁

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int nready = 0;
struct timespec timestamp;

// 模式1:抢锁冲突严重
void *producter(void *arg)
{
    char date_time[64];
    struct tm t;
    while (1)
    {
        pthread_mutex_lock(&mutex);
        if (nready >= 1) {
            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("producer tid=%d, before notify, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

            pthread_cond_signal(&cond);
            //sleep(10); 

            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("producer tid=%d, after notify, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);
        }
        nready++;

        clock_gettime(CLOCK_REALTIME, &timestamp);
        strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
        printf("producer tid=%d, will unlock, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

        pthread_mutex_unlock(&mutex);
        sleep(2);
        //sched_yield(); // 与让不让cpu无关
    }
 
    return NULL;
}

// 模式2:避免抢锁冲突
void *producter(void *arg)
{
    char date_time[64];
    struct tm t;
    while (1)
    {
        pthread_mutex_lock(&mutex);

        nready++;

        clock_gettime(CLOCK_REALTIME, &timestamp);
        strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
        printf("producer tid=%d, will unlock, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

        pthread_mutex_unlock(&mutex);

        if (nready >= 1) {
            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("producer tid=%d, before notify, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

            pthread_cond_signal(&cond);
            //sleep(10);

            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("producer tid=%d, after notify, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);
        }
        
        //sched_yield(); // 与让不让cpu无关
    }
 
    return NULL;
}

 
void *consumer(void *arg)
{
    char date_time[64];
    struct tm t;
    while (1) {
        pthread_mutex_lock(&mutex);
        while (nready <= 0) {
            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("consumer tid=%d, will sleep, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

            pthread_cond_wait(&cond, &mutex);

            clock_gettime(CLOCK_REALTIME, &timestamp);
            strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
            printf("consumer tid=%d, wait return, in while, already awake up, and get lock, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);
        }

        clock_gettime(CLOCK_REALTIME, &timestamp);
        strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
        printf("consumer tid=%d, wait return, out while, already awake up, and get lock, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

        nready--;

        clock_gettime(CLOCK_REALTIME, &timestamp);
        strftime(date_time, sizeof(date_time), "%Y-%m-%d %H:%M:%S", localtime_r(&timestamp.tv_sec, &t));
        printf("consumer tid=%d, wait return, out while, after --nready, already awake up, and get lock, clock_gettime: date_time=%s, tv_nsec=%ld, nready=%d.\n", pthread_self(), date_time, timestamp.tv_nsec, nready);

        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}
 
int main(void)
{
    int pthread_num = 1;
    pthread_t ptid[pthread_num];
    pthread_t ctid[pthread_num];

    int i = 0;
    for (i = 0; i < pthread_num; i++) {
        pthread_create(&ctid[i], NULL, consumer, NULL);
    }

    for (i = 0; i < pthread_num; i++) {
        pthread_create(&ptid[i], NULL, producter, NULL);
    }

    for (i = 0; i < pthread_num; i++) {
        pthread_join(ctid[i], NULL);
    }

    for (i = 0; i < pthread_num; i++) {
        pthread_join(ptid[i], NULL);
    }
    return 0;
}

模式1:抢锁冲突严重

1,pthread_cond_wait 解锁和阻塞这两个步骤是原子的。但是被唤醒和上锁不是原子的,需要等生产者解锁后,才会去抢互斥锁(消费者和生产者抢锁,以及消费者之间抢锁)。

2,处于互斥锁中的pthread_cond_signal 发送信号, pthread_cond_wait被唤醒后,需要等发送信号的那个生产者解锁后,才会去抢互斥锁(消费者和生产者抢锁,以及消费者之间抢锁)。

// 生产者及时发送信
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值