线程同步与条件变量

1 为什么需要线程同步?

当多个线程同时访问共享资源时,可能会出现:

  • 竞态条件:执行结果依赖于线程执行的顺序
  • 数据不一致:线程读取到中间状态的数据
  • 死锁:线程相互等待对方释放资源

2 同步概念与竞态条件

• 同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步

• 竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也不难理解

3 条件变量

• 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。

• 例如一个线程访问队列时,发现队列为空,它只能等待,等到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

基本概念:

条件变量是多线程编程中的同步机制,用于线程间的通信和协调。它允许一个或多个线程等待某个条件成立,而其他线程在条件满足时通知等待的线程。

核心功能

1. 等待条件

  • 线程检查条件,如果条件不满足,则进入等待状态
  • 等待时会自动释放互斥锁,让其他线程能修改共享数据

2. 通知等待线程

  • signal():唤醒一个等待线程
  • broadcast():唤醒所有等待线程

3 条件变量函数

初始化

条件变量的初始化和互斥锁几乎一样

• 方法1,静态分配:

cpp 复制代码
// 静态初始化(全局或静态变量)
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// 不需要调用 pthread_cond_init
// 也不需要调用  pthread_cond_destroy

方法2,动态分配: pthread_cond_init 函数

pthread_cond_init是 POSIX 线程库中用于初始化条件变量的函数。条件变量用于线程间的同步,允许线程等待某个条件成立。

cpp 复制代码
#include <pthread.h>

int pthread_cond_init(pthread_cond_t *restrict cond,
                     const pthread_condattr_t *restrict attr);

参数说明

cond

  • 指向要初始化的条件变量的指针

attr

  • 指向条件变量属性的指针
  • 如果为 NULL,则使用默认属性

返回值

  • 成功:返回 0
  • 失败:返回错误码(非零值)

销毁

cpp 复制代码
int pthread_cond_destroy(pthread_1 cond_t *cond)

等待

pthread_cond_wait是 POSIX 线程(pthread)库中用于条件变量等待的函数。

cpp 复制代码
#include <pthread.h>

int pthread_cond_wait(pthread_cond_t *restrict cond,
                      pthread_mutex_t *restrict mutex);

参数说明

参数 说明
cond 指向条件变量的指针
mutex 指向互斥锁的指针

工作原理

1. 原子操作三部曲

当线程调用 pthread_cond_wait 时,它会原子地执行以下操作:

cpp 复制代码
// 伪代码表示其行为:
pthread_mutex_unlock(mutex);    // 1. 释放互斥锁
wait_for_signal(cond);          // 2. 等待条件变量
pthread_mutex_lock(mutex);      // 3. 重新获取互斥锁

2. 为什么要用互斥锁配合?

条件变量必须与互斥锁一起使用,原因:

  • 防止竞争条件(race condition)
  • 确保检查条件和等待是原子操作
  • 避免信号丢失

唤醒等待

cpp 复制代码
int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒在该条件变量下等待的全部线程
//唤醒在该条件变量下等待的一个线程
int pthread_cond_signal(pthread_cond_t *cond);

代码实践:简单看一下函数应用

cpp 复制代码
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *active(void *arg)
{
    std::string name = static_cast<const char *>(arg);
    while (true)
    {
        pthread_mutex_lock(&mutex);
        pthread_cond_wait(&cond, &mutex);
        std::cout << name << " 活动..." << std::endl;
        pthread_mutex_unlock(&mutex);
    }
}
int main(void)
{
    pthread_t t1, t2;
    pthread_create(&t1, NULL, active, (void *)"thread-1");
    pthread_create(&t2, NULL, active, (void *)"thread-2");
    sleep(3); // 可有可无,这里确保两个线程已经在运行
    while (true)
    {
        // 对比测试
        //pthread_cond_signal(&cond); // 唤醒一个线程
        pthread_cond_broadcast(&cond); // 唤醒所有线程
        sleep(1);
    }
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}

当唤醒一个线程时一个线程一个线程逐个出现,当唤醒所有线程时两个两个的一起出现

相关推荐
至善迎风5 小时前
Linux 服务器安全防护工具完全指南
linux·服务器·安全·防火墙
MC皮蛋侠客5 小时前
Linux安装go及环境配置教程
linux·运维·golang
Ayanami_Reii5 小时前
进阶数据结构-AC自动机
数据结构·算法·动态规划·字符串·ac自动机
崇山峻岭之间5 小时前
C++ Prime Plus 学习笔记030
c++·笔记·学习
带鱼吃猫5 小时前
数据结构:顺序表与基于动态顺序表的通讯录项目
数据结构·链表
报错小能手5 小时前
数据结构 AVL二叉平衡树
数据结构·算法
满天点点星辰5 小时前
Linux命令大全-find命令
linux·运维·服务器
H_z_q24015 小时前
RHCE的条件测试
linux·运维·服务器
新青年.5 小时前
【Ubuntu】Ubuntu下解决Chrome不能输入中文
linux·chrome·ubuntu