pthread_cond_wait详解

本文详细介绍了pthread条件变量和互斥锁的使用方法,包括初始化、等待、唤醒及销毁等关键步骤,并通过实例展示了如何利用这些机制实现线程间的同步。
该文章已生成可运行项目,

    通常,和pthread _cond_wait 配对使用的有pthread_cond_signal , 同时还有用于pthread_cond_t初始化的pthread_cond_init,销毁的pthread_cond_destroy函数,还有用于加锁保护的pthread_mutex_lock和pthread_mutex_unlock,稍后会对为什么进行加锁做解释。

     初始化条件变量int pthread_cond_init(pthread_cond_t *cv, pthread_cond_attr *cattr); 

     函数返回值:返回0表示成功,其他都表示失败。对于函数的参数:pthread_cond_attr 是用来设置pthread_cond_t的属性,当传入的值是NULL的时候表示使用默认的属性。这个函数返回时,创建的条件变量保存在cv所指向的内存中。可以用宏PTHREAD_COND_INITIALIZER来初始化条件变量。但是请记住不能用多个线程初始化同一个条件变量,当一个线程要使用条件变量的时候确保它是未被使用的。

    条件变量的销毁:int pthread_cond_destroy(pthread_cond_t *cv); 返回0表示成功,返回其他值都表示失败。

    条件变量的使用: int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)以及 int pthread_cond_signal(pthread_cond_t *cv);

    使用pthread_cond_wait方式如下:

    pthread _mutex_lock(&mutex)

    while或if(线程执行的条件是否成立)

          pthread_cond_wait(&cond, &mutex);

    线程执行

    pthread_mutex_unlock(&mutex);

   

    需要解释的有两点,为什么要加锁,以及为什么可以使用while和if。首先解释第一点,有两个方面,线程在执行的部分访问的是进程的资源,有可能有多个线程需要访问它,为了避免由于线程并发执行所引起的资源竞争,所以要让每个线程互斥的访问公有资源,但是细心一下就会发现,如果while或者if判断的时候,不满足线程的执行条件,那么线程便会调用pthread_cond_wait阻塞自己,但是它持有的锁怎么办呢,如果他不归还操作系统,那么其他线程将会无法访问公有资源。这就要追究一下pthread_cond_wait的内部实现机制,当pthread_cond_wait被调用线程阻塞的时候,pthread_cond_wait会自动释放互斥锁。释放互斥锁的时机是什么呢:是线程从调用pthread_cond_wait到操作系统把他放在线程等待队列之后,这样做有一个很重要的原因,就是mutex的第二个作用,保护条件。想一想,线程是并发执行的,如果在没有把被阻塞的线程A放在等待队列之前,就释放了互斥锁,这就意味着其他线程比如线程B可以获得互斥锁去访问公有资源,这时候线程A所等待的条件改变了,但是它没有被放在等待队列上,导致A忽略了等待条件被满足的信号。倘若在线程A调用pthread_cond_wait开始,到把A放在等待队列的过程中,都持有互斥锁,其他线程无法得到互斥锁,就不能改变公有资源。这就保证了线程A被放在等待队列上之后才会有公有资源被改变的信号传递给等待队列。对于这点apue给出的解释:The mutex passed to pthread_cond_wait protects the condition.The caller passes it locked to the function, which then atomically places the calling thread on

 the list of threads waiting for the condition and unlocks the mutex. This closes the window between the time that the condition is checked and the time that the

 thread goes to sleep waiting for the condition to change, so that the thread doesn't miss a change in the condition. When pthread_cond_wait returns, 

the mutex is again locked.

   接下来讲解使用while和if判断线程执行条件是否成立的区别。一般来说,在多线程资源竞争的时候,在一个使用资源的线程里面(消费者)判断资源是否可用,不可用便调用pthread_cond_wait,在另一个线程里面(生产者)如果判断资源可用的话,则调用pthread_cond_signal发送一个资源可用信号。但是在wait成功之后,资源就一定可以被使用么,答案是否定的,如果同时有两个或者两个以上的线程正在等待此资源,wait返回后,资源可能已经被使用了,在这种情况下,应该使用:

while(resource == FALSE)

      pthread_cond_wait(&cond, &mutex);

如果之后一个消费者,那么使用if就可以了。解释一下原因,分解pthread_cond_wait的动作为以下几步:

1,线程放在等待队列上,解锁

2,等待 pthread_cond_signal或者pthread_cond_broadcast信号之后去竞争锁

3,若竞争到互斥索则加锁。

上面讲到,有可能多个线程在等待这个资源可用的信号,信号发出后只有一个资源可用,但是有A,B两个线程都在等待,B比较速度快,获得互斥锁,然后加锁,消耗资源,然后解锁,之后A获得互斥锁,但他回去发现资源已经被使用了,它便有两个选择,一个是去访问不存在的资源,另一个就是继续等待,那么继续等待下去的条件就是使用while,要不然使用if的话pthread_cond_wait返回后,就会顺序执行下去。

    下面来讲一下:pthread_cond_wait和pthread_cond_singal是怎样配对使用的:

     等待线程:

     pthread_cond_wait前要先加锁
     pthread_cond_wait内部会解锁,然后等待条件变量被其它线程激活
     pthread_cond_wait被激活后会再自动加锁
     激活线程:
     加锁(和等待线程用同一个锁)
     pthread_cond_signal发送信号
     解锁
     激活线程的上面三个操作在运行时间上都在等待线程的pthread_cond_wait函数内部。

    

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  cond  = PTHREAD_COND_INITIALIZER;

int count = 0;

void *decrement(void *arg) {
    printf("in derement.\n");
    pthread_mutex_lock(&mutex);
    if (count == 0)
        pthread_cond_wait(&cond, &mutex);
    count--;
    printf("----decrement:%d.\n", count);
    printf("out decrement.\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void *increment(void *arg) {
    printf("in increment.\n");
    pthread_mutex_lock(&mutex);
    count++;
    printf("----increment:%d.\n", count);
    if (count != 0)
        pthread_cond_signal(&cond);
    printf("out increment.\n");
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t tid_in, tid_de;
    pthread_create(&tid_de, NULL, (void*)decrement, NULL);
    sleep(2);
    pthread_create(&tid_in, NULL, (void*)increment, NULL);
    sleep(5);
    pthread_join(tid_de, NULL);
    pthread_join(tid_in, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}
这个例子中, decrement函数中也可以使用while,读者可以换一下试试。

然后在给出一个生产者消费者的例子:

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

typedef struct node_s {
    int data;
    struct node_s *next;
}node_t;

node_t *head = NULL;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition = PTHREAD_COND_INITIALIZER;

void cleanup_handler(void *arg) {
    printf("cleanup_handler is running.\n");
    free(arg);
    pthread_mutex_unlock(&mutex);
}

void *thread_func(void *arg) {
    node_t *p = NULL;
    pthread_cleanup_push(cleanup_handler, p);
    while (1) {
        pthread_mutex_lock(&mutex);
        while (NULL == head)
            pthread_cond_wait(&condition, &mutex);
        p = head;
        head = head->next;
        printf("process %d node.\n", p->data);
        free(p);
        pthread_mutex_unlock(&mutex);
    }
    pthread_cleanup_pop(0);
    return NULL;
}

int main(int argc, char *argv[]) {
    pthread_t tid;
    node_t *temp = NULL;
    int i;
    pthread_create(&tid, NULL, (void*)thread_func, NULL);
    for (i = 0; i < 10; i++) {
        temp = (node_t*)malloc(sizeof(node_t));
        temp->data = i;
        pthread_mutex_lock(&mutex);
        temp->next = head;
        head = temp;
        pthread_cond_signal(&condition);
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
    pthread_cancel(tid);
    pthread_join(tid, NULL);
    return 0;
}

其中的 pthread _cleanup_push  和 pthread_cleanup_pop,pthread_cancel作为下次博客讲解的内容。

本文章已经生成可运行项目
内容概要:本文围绕基于CNN-Transformer混合模型的锂电池SOH(State of Health,健康状态)预测估计展开研究,提出一种融合卷积神经网络(CNN)与Transformer架构的深度学习方法,用于精准建模电池容量衰退过程。该方法充分发挥CNN在局部特征提取方面的优势以及Transformer在捕捉长时间序列依赖关系上的强大能力,有效提升了锂电池健康状态预测的准确性与稳定性。研究内容涵盖数据预处理、模型结构设计、训练优化流程及预测结果可视化等关键环节,适用于电池退化趋势分析与剩余使用寿命(RUL)评估,具有较强的工程应用价值。; 适合人群:具备Python编程能力和深度学习理论基础的高校研究生、科研人员及从事新能源电池管理系统开发的工程技术人才,特别适合聚焦于锂电池寿命预测、故障诊断与健康管理等方向的研究者。; 使用场景及目标:①掌握CNN与Transformer在时间序列回归任务中的协同建模机制;②实现高精度锂电池SOH预测模型构建与训练;③服务于电动汽车续航管理、储能系统运维决策与电池老化特性分析;④支持学术论文复现、科研项目验证及工业级电池管理算法开发。; 阅读建议:此资源以代码实践为核心驱动,建议读者结合所提供的完整Python代码进行动手实现,深入理解模型各模块的设计逻辑与训练技巧,并可通过调整网络结构或引入新数据集进一步拓展至其他时序预测任务中。
我们把同一标的(昆仑万维,现价 43.20 元,2026-07-31 收盘)交给三套系统,各出一份独立分析: **C 报告(CoordClaw 基于管理学多智能体系统)**——投研级。它由五个角色构成:周婷整合撰写、李静出基本面、王芳出技术面、赵明出风险、陈默做 PM 终审。最终产物是一份 38 项分级风险清单(P0×4 / P1×12 / P2×12 / P3×6 / 尾部×4)、双源交叉验证的财务数据(EM/Sina 差异 <0.01%)、严格的口径纪律,以及一份原样保留的"待核实"清单。结论冷冰冰:高风险,不建议参与。 **D 报告(DeepSeek)**——信息整理级。它把"4+3 AGI 战略"、天工 AI、Opera 浏览器、StarMaker 拆得很漂亮,核心财务数据(营收 81.98 亿、归母 -15.93 亿)也没算错。但整篇没有技术面、没有量化风控,更关键的是——它完全没提实控人已减持 75%、质押状态未知、净现金仅 15.19 亿且续航只有 1.26~1.81 年这些要命的负面。这是典型的"选择性呈现"。 **K 报告(Kimi)**——以对比评估的方式呈现。它搭起"数据准确性 / 分析维度 / 结论合理性"的三维框架,把几份材料放在一起对照,给出各自的强弱判定。它的维度意识比 D 报告更自觉,但作为一份独立分析,它对"评估方法本身的信度"交待不足,部分引用的核对也不够彻底。 结果两家的结论高度一致。C 报告(多智能体)被评投研级、居首;D 报告(DeepSeek 自己写的)被评信息整理级、居中;K 报告(Kimi 自己那份)维度较全但核验深度有限,排在两者之间。DeepSeek 的那份评估把 C 给了五星、D 三星、K 四星;Kimi 的那份评估也独立地把最高分给了 C。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值