当前位置: 首页 > news >正文

C++:std::thread、条件变量与信号量

介绍

在多线程编程的世界里,协调不同线程之间的工作是一项极具挑战性的任务。线程可能需要等待特定条件的满足,或者对共享资源的访问进行限制。C++ 标准库为我们提供了强大的工具,如 std::thread 用于创建和管理线程,条件变量用于线程间的同步,信号量则用于控制对资源的访问。本文将通过具体的 C++ 代码示例,详细介绍如何使用这些工具。

std::thread 基础

std::thread 是 C++11 引入的用于创建和管理线程的类。它允许我们轻松地在程序中创建新的执行线程。下面是一个简单的 std::thread

#include <iostream>
#include <thread>

void printMessage(const std::string& message) {
    std::cout << "Thread says: " << message << std::endl;
}

int main() {
    std::thread t(printMessage, "Hello, World!");
    t.join();
    return 0;
}

定义了一个函数 printMessage,然后使用 std::thread 创建了一个新线程,并将 printMessage 函数作为线程的入口点,同时传递了一个字符串参数。join() 方法用于等待线程执行完毕。

条件变量

条件变量是一种同步原语,用于线程之间的通信和协调。它允许一个线程等待某个条件的满足,而另一个线程可以在条件满足时通知等待的线程。
生产者 - 消费者模型示例
生产者 - 消费者模型是多线程编程中常见的模式,生产者线程负责生产数据,消费者线程负责消费数据。我们可以使用条件变量来实现线程间的同步。

#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

std::queue<int> dataQueue;
std::mutex mtx;
std::condition_variable cv;
bool isProducing = true;

// 生产者线程函数
void producer() {
    for (int i = 0; i < 5; ++i) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        {
            std::unique_lock<std::mutex> lock(mtx);
            dataQueue.push(i);
            std::cout << "Produced: " << i << std::endl;
        }
        cv.notify_one();
    }
    {
        std::unique_lock<std::mutex> lock(mtx);
        isProducing = false;
    }
    cv.notify_one();
}

//消费者线程函数
void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return!dataQueue.empty() ||!isProducing; });
        if (!dataQueue.empty()) {
            int value = dataQueue.front();
            dataQueue.pop();
            std::cout << "Consumed: " << value << std::endl;
        } else if (!isProducing) {
            break;
        }
    }
}

int main() {
    std::thread producerThread(producer);
    std::thread consumerThread(consumer);

    producerThread.join();
    consumerThread.join();

    return 0;
}

std::queue dataQueue:用于存储生产者生产的数据。
std::mutex mtx:用于保护对 dataQueue 的访问,确保线程安全。
std::condition_variable cv:用于线程间的同步。
producer() 函数:生产者线程每隔 1 秒生产一个数据,并将其加入队列。生产完成后,通知消费者线程。
consumer() 函数:消费者线程等待条件变量的通知,当队列中有数据时,从队列中取出数据进行消费。
cv.wait(lock, [] { return!dataQueue.empty() ||!isProducing; }):消费者线程等待,直到队列非空或者生产结束。

信号量

信号量是一种用于控制对资源访问的同步原语。在 C++ 标准库中,并没有直接提供信号量的实现,可以使用 std::mutex 和 std::condition_variable 来模拟信号量。
信号量的实现

#include <mutex>
#include <condition_variable>

class Semaphore {
public:
    Semaphore(int count = 0) : count_(count) {}

    void notify() {
        std::unique_lock<std::mutex> lock(mtx_);
        ++count_;
        cv_.notify_one();
    }

    void wait() {
        std::unique_lock<std::mutex> lock(mtx_);
        cv_.wait(lock, [this] { return count_ > 0; });
        --count_;
    }

private:
    int count_;
    std::mutex mtx_;
    std::condition_variable cv_;
};
#include <iostream>
#include <thread>
#include <vector>

Semaphore sem(2); // 允许最多 2 个线程同时访问资源

void accessResource(int id) {
    sem.wait();
    std::cout << "Thread " << id << " is accessing the resource." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "Thread " << id << " has finished accessing the resource." << std::endl;
    sem.notify();
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back(accessResource, i);
    }

    for (auto& t : threads) {
        t.join();
    }

    return 0;
}

Semaphore 类:实现了一个简单的信号量。notify() 方法用于增加信号量的值并通知等待的线程,wait() 方法用于等待信号量的值大于 0 并减少信号量的值。
accessResource() 函数:线程在访问资源前调用 sem.wait() 等待信号量,访问完成后调用 sem.notify() 释放信号量。
emplace_back 是 C++ 标准库容器(如 std::vector、std::deque 等)提供的一个成员函数,它主要用于在容器的尾部直接构造一个新元素。

结论

通过 std::thread、条件变量和信号量,可以在 C++ 中实现复杂的多线程程序。条件变量用于线程间的同步,确保线程在特定条件满足时才继续执行;信号量用于控制对资源的访问,避免资源竞争。合理使用这些工具可以提高程序的性能和稳定性。希望本文能帮助你更好地理解和应用这些多线程编程的重要概念。

相关文章:

  • 【网络】高级IO——Reactor版TCP服务器
  • 【学习笔记】Cadence电子设计全流程(二)原理图库的创建与设计(5-7)
  • 【JT/T 808协议】808 协议开发笔记 ② ( 终端注册 | 终端注册应答 | 字符编码转换网站 )
  • MongoDB应用设计调优
  • 【Leetcode 每日一题 - 扩展】1512. 好数对的数目
  • 鸿蒙NEXT应用App测试-专项测试(DevEco Testing)
  • 【Elasticsearch】同一台服务器部署集群
  • Java IO 设计模式总结
  • Plant Simulation培训教程-机器人3D仿真模块
  • C# AOT技术测试
  • DeepSeek 全面分析报告
  • 大语言模型微调的公开JSON数据
  • 业务流程相关的权威认证和培训有哪些
  • DeepSeek新作-Native Sparse Attention
  • 蓝桥杯之枚举
  • HTML Application(hta)入门教程
  • vue3页面显示tiff图片
  • 解析HTML时需要注意什么?
  • 微软发布Majorana 1芯片,开启量子计算新路径
  • 手动搭建Redis1主2从+ 3 Sentinel 高可用集群
  • 欧盟公布关税反制清单,瞄准美国飞机、汽车等产品
  • 读图|展现城市品格,上海城市影像走进南美
  • 华为鸿蒙电脑正式亮相,应用生态系统能否挑战Windows?
  • 国新办将于5月8日10时就《民营经济促进法》有关情况举行新闻发布会
  • 长三角铁路五一假期发送旅客超2000万人次,同比增幅超一成
  • 山东滕州车祸致6人遇难,醉驾肇事司机已被刑事拘留