C++多线程 条件等待和通知

std::condition_variable 是 C++11 引入的一个重要工具,用于多线程编程中的线程同步。它通常与 std::mutex 一起使用,帮助线程在特定条件满足时等待或唤醒。以下是一个简单的示例,展示了如何在 C++ 中使用 std::condition_variable

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

std::mutex mtx; // 互斥量,用于保护共享数据
std::condition_variable cv; // 条件变量

bool data_ready = false; // 共享数据,表示数据是否准备就绪

void producer_function() {
    // 模拟生产数据的过程
    std::this_thread::sleep_for(std::chrono::seconds(1));
    
    // 通过互斥量锁定,修改共享数据
    {
        std::lock_guard<std::mutex> lock(mtx);
        data_ready = true;
    }
    
    // 通知等待的消费者线程
    cv.notify_one();
}

void consumer_function() {
    // 等待数据准备就绪
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return data_ready; }); // 等待条件变量满足

    // 处理数据
    std::cout << "Consumer thread: Data is ready!\n";
}

int main() {
    // 创建生产者和消费者线程
    std::thread producer(producer_function);
    std::thread consumer(consumer_function);

    // 等待线程结束
    producer.join();
    consumer.join();

    return 0;
}

这个例子中,主线程创建了一个生产者线程和一个消费者线程。生产者线程在一秒钟后将 data_ready 设置为 true,然后通过 cv.notify_one() 通知消费者线程。消费者线程使用 cv.wait()data_ready 变为 true 之前等待,并在条件满足后输出消息。

这种结构允许线程在需要等待某些条件满足时暂时挂起,而不是通过轮询来浪费处理器资源。

std::condition_variablewait 函数内部并不是使用轮询来实现的。它的实现通常依赖于操作系统提供的原生线程同步机制,比如 POSIX 线程库中的条件变量。具体来说,std::condition_variablewait 函数会在等待条件不满足时将当前线程置于休眠状态,并释放所关联的互斥量。当其他线程通过 notify_one()notify_all() 发送信号时,等待的线程会被唤醒并重新获取互斥量,然后重新检查条件是否满足。

这种方式避免了线程轮询,因此可以显著减少不必要的 CPU 消耗,提高了多线程程序的效率和性能。

std::condition_variable::wait() 函数需要一个互斥量来保护条件变量的等待操作。std::unique_lock 可以在构造时将互斥量锁定,并在 wait() 函数内部自动释放锁,这符合条件变量等待操作的要求。

### C++多线程事件监听与通知机制的实现 在 C++ 中,可以利用标准库中的 `std::thread` 同步工具(如条件变量 `std::condition_variable` 或互斥锁 `std::mutex`)来构建一个多线程的事件监听与通知机制。以下是具体实现的方式: #### 使用条件变量互斥锁 通过 `std::condition_variable` 可以让某些线程等待特定事件的发生,而其他线程则负责触发这些事件。 ```cpp #include <iostream> #include <vector> #include <thread> #include <queue> #include <functional> #include <mutex> #include <condition_variable> class EventListener { public: void registerCallback(const std::function<void()>& callback) { std::lock_guard<std::mutex> lock(mutex_); callbacks_.push_back(callback); } void triggerEvent() { std::unique_lock<std::mutex> lock(mutex_); triggered_ = true; cv_.notify_all(); // 唤醒所有等待的线程 } private: bool isTriggered() const { return triggered_; } void resetTrigger() { triggered_ = false; } std::vector<std::function<void()>> callbacks_; mutable std::mutex mutex_; std::condition_variable cv_; bool triggered_ = false; friend class EventHandler; }; class EventHandler { public: EventHandler(EventListener& listener) : listener_(listener) {} void startListening() { while (true) { std::unique_lock<std::mutex> lock(listener_.mutex_); listener_.cv_.wait(lock, [&]() { return listener_.isTriggered(); }); if (listener_.isTriggered()) { for (const auto& callback : listener_.callbacks_) { callback(); } listener_.resetTrigger(); } } } private: EventListener& listener_; }; ``` 上述代码展示了如何创建一个简单的事件监听器类 `EventListener` 处理器类 `EventHandler`。 - **注册回调**:任何线程都可以向 `EventListener` 注册回调函数。 - **触发事件**:当某个事件发生时,调用 `triggerEvent()` 方法唤醒所有正在等待该事件的线程并执行已注册的回调函数[^1]。 #### 单线程同时监听多个端口的情况 对于需要在一个线程中同时监听多个端口的需求,可以考虑使用 I/O 复用技术(如 `select`、`poll` 或 `epoll`)。然而,在 Windows 平台上更推荐使用重叠 I/O 或者 IOCP(I/O Completion Ports)。下面是一个基于传统方法的例子——每监听一个端口启动一个新的线程[^2]。 ```cpp #include <winsock2.h> #include <ws2tcpip.h> #include <iostream> #include <thread> #include <vector> #pragma comment(lib,"Ws2_32.lib") void listenOnPort(unsigned short port) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in service {}; service.sin_family = AF_INET; service.sin_addr.s_addr = INADDR_ANY; service.sin_port = htons(port); bind(serverSocket, reinterpret_cast<SOCKADDR*>(&service), sizeof(service)); listen(serverSocket, SOMAXCONN); std::cout << "Listening on port: " << port << "\n"; while (true) { SOCKET clientSocket = accept(serverSocket, nullptr, nullptr); if (clientSocket != INVALID_SOCKET) { char buffer[1024]; int bytesReceived = recv(clientSocket, buffer, sizeof(buffer) - 1, 0); if (bytesReceived > 0) { buffer[bytesReceived] = '\0'; std::cout << "Message from client (" << port << "): " << buffer << "\n"; } closesocket(clientSocket); } else { std::cerr << "Accept failed with error: " << WSAGetLastError() << "\n"; } } closesocket(serverSocket); } int main() { unsigned short ports[] = {8080, 9090, 7070}; // 需要监听的端口号列表 std::vector<std::thread> threads; for (auto port : ports) { threads.emplace_back(listenOnPort, port); } for (auto& thread : threads) { thread.join(); } WSACleanup(); } ``` 此程序会在指定的一组端口上分别开启监听服务,并为每个端口分配独立的工作线程。这种方式适合于少量端口监听场景,但如果端口数量较多,则可能带来较大的性能开销。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值