#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
// Define a message structure
struct Message {
int senderId;
std::string content;
};
// Global variables for synchronization
std::mutex mtx;
std::condition_variable cv;
std::queue<Message> messageQueue;
// Function for sending a message
void sendMessage(int senderId, const std::string& content) {
std::lock_guard<std::mutex> lock(mtx);
messageQueue.push({senderId, content});
cv.notify_one(); // Notify the waiting thread
}
// Function for receiving a message
void receiveMessage(int receiverId) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !messageQueue.empty(); }); // Wait until there is a message
// Process the message
Message msg = messageQueue.front();
messageQueue.pop();
// Check if the message is for this receiver
if (msg.senderId == receiverId) {
std::cout << "Received message: " << msg.content << std::endl;
} else {
std::cout << "Message not for this receiver" << std::endl;
}
}
int main() {
// Create sender and receiver threads
std::thread senderThread([] {
sendMessage(1, "Hello from sender");
sendMessage(2, "Hello from sender");
});
std::thread receiverThread1([] {
receiveMessage(1);
});
std::thread receiverThread2([] {
receiveMessage(2);
});
// Join threads
senderThread.join();
receiverThread1.join();
receiverThread2.join();
return 0;
}
这个例子中:
①. 定义一个 Message 结构来保存发送者ID信息和内容的相关信息。
②. 全局变量 mtx , cv 和 messageQueue 用于同步。 mtx 是std::mutex变量, cv 是std::condition_variable变量, messageQueue 是用于存储消息的std::queue队列。
③. 线程使用 sendMessage 函数发送消息。它锁定互斥项,将消息推入队列,并使用条件变量通知等待的线程。
④. receiveMessage 函数用于线程接收消息。它使用条件变量等待队列中出现消息。一旦有消息,它就会处理该消息。
⑤. 在 main 函数中,我们创建了发送者和接收者线程,以演示线程之间的消息传递。
本示例说明了使用消息对同步线程的基本方法。根据您的具体要求和使用情况,您可能需要修改或扩展这种方法。
std::queue和std::deque,在C++中哪个更好?
在 C++ 中, std::queue 和 std::deque 的作用各不相同,是否适用取决于应用程序的具体需求:
①. std::deque (双端队列)是一种允许在前后两端插入和删除的容器。其实现方式是在两端快速插入和删除。 std::deque 是一种序列容器,可以像动态数组一样使用,并能在两端增长和收缩。
②. std::queue 是一种容器适配器,为您提供 FIFO(先进先出)行为。它通常使用 std::deque 或 std::list 作为底层容器,提供一系列受限的操作,如 enqueue(推送)、dequeue(弹出)和 front。
哪个更好?
①. 性能考虑因素:如果需要在序列两端快速插入和删除,那么 std::deque 是更好的选择。但是,如果只需要在后端插入并从前端删除, std::queue 则为先进先出队列提供了更合适、语义更清晰的接口。
②. 内存效率:与基于 std::list 的 std::queue 相比, std::deque 可能会更有效地使用内存。std::deque的效率更高,因为std::deque以块为单位分配元素,与std::list 相比,减少了开销,因为 std::list 中的每个元素都需要分配自己的内存。
③. 功能需求:如果您需要一个简单的队列结构,并且不需要访问容器的中间部分, std::queue 是合适的选择。如果您需要更灵活的操作,如访问中间的元素、从两端插入或移除元素,那么 std::deque 会更好。
④. 语义清晰:使用 std::queue 可以清楚地表明您使用的是先进先出数据结构,这可以使代码更容易理解,而 std::deque 则更为通用,并不暗示特定的使用模式。
总之,选择 std::queue 还是 std::deque 取决于您的具体需求。如果您需要简单的 FIFO 结构, std::queue 是典型的选择。如果您需要在两端插入和删除数据时具有更高的灵活性和性能, std::deque 则是更好的选择。
在一个类中定义
为了将同步机制和缓冲区管理封装在一个类中,我们可以定义一个类来管理共享缓冲区,并提供线程安全的方法来生成和消耗项目。下面是定义此类的方法:
①. Buffer Class:该类将包含作为缓冲区的 std::deque 以及用于同步的 std::mutex 和 std::condition_variable 。
②. 生产者和消费者方法:这些方法是类的一部分,将使用同步原语安全地访问缓冲区。
下面是一个如何定义和使用这种类的示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
class SynchronizedBuffer {
private:
std::mutex mtx;
std::condition_variable cv;
std::deque<int> buffer;
const size_t maxSize;
bool finished;
public:
SynchronizedBuffer(size_t maxSize) : maxSize(maxSize), finished(false) {}
void produce(int item) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this] { return buffer.size() < maxSize; });
buffer.push_back(item);
std::cout << "Produced: " << item << std::endl;
lock.unlock();
cv.notify_one();
}
int consume() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this] { return !buffer.empty() || finished; });
if (buffer.empty()) {
return -1; // or other sentinel value indicating no more items will be produced
}
int item = buffer.front();
buffer.pop_front();
std::cout << "Consumed: " << item << std::endl;
lock.unlock();
cv.notify_one();
return item;
}
void finish() {
std::unique_lock<std::mutex> lock(mtx);
finished = true;
cv.notify_all();
}
};
void producer(SynchronizedBuffer& buffer, int start, int end) {
for (int i = start; i < end; ++i) {
buffer.produce(i);
}
buffer.finish();
}
void consumer(SynchronizedBuffer& buffer) {
while (true) {
int item = buffer.consume();
if (item == -1) break;
// Process the item
}
}
int main() {
SynchronizedBuffer buffer(10);
std::thread prod1(producer, std::ref(buffer), 0, 50);
std::thread cons1(consumer, std::ref(buffer));
prod1.join();
cons1.join();
return 0;
}
finish方法允许生产者发出不再生产项目的信号,这有助于优雅地终止消费者线程。
这种结构将同步逻辑封装在 SynchronizedBuffer 类中,使多线程逻辑更易于管理和理解。