我试图编写一个简单的示例,说明生产者和消费者两个线程之间的经典通信。生产者锁定互斥锁,生成随机字符串消息,并将其推入队列并释放锁。然后,使用者锁定互斥锁并将该数据打印在屏幕上。由于某种原因,在运行代码后,我有时会出现空白终端,然后程序终止,没有任何输出!这是我的代码:
#include <iostream>
#include <stdlib.h>
#include <thread>
#include <mutex>
#include <queue>
#include <random>
#include <string>
#include <cstdlib>
using namespace std;
static mutex mmutex;
static condition_variable mcond;
static queue <string> mqueue;
void consumer() {
while (true) {
unique_lock<mutex> lck{mmutex};
mcond.wait(lck);
string new_string = "producer has not produced yet ";
string m = "";
if (!mqueue.empty()) {
m = mqueue.front();
mqueue.pop();
string new_string = "producer produced " + m;
}
cout << new_string << endl;
lck.unlock();
}
}
void producer() {
while (true) {
string new_msg = NULL;
unique_lock<mutex> lck{mmutex};
int random = rand() % 40 + 40;
new_msg = "New Random Char is "+static_cast <char> (random);
mqueue.push(new_msg);
mcond.notify_one();
}
}
int main() {
thread t1{ producer };
thread t2{ consumer };
t1.join();
t2.join();
cout << "exiting"<<endl;
system("PAUSE");
exit(0);
}
答案 0 :(得分:2)
总体而言,您将获得同步方案。除此之外,该代码存在一个运行时错误,使用std::string
会产生一些意想不到的后果,并且在{{1}上对unlock()
的不必要调用会导致: }。
运行代码后,我得到空白终端一段时间,然后 程序终止而没有任何输出
由于将指向null的指针分配给std::unique_ptr
,它挂起并终止:
std::string
您可以see here,这将导致string new_msg = NULL;
实例尝试访问该地址零:(
第二,您无法通过将字符串文字与std::string
进行连接来获得所需的内容,如下所示:
char
和
string new_string = "producer produced " + m;
这是您的线程过程的工作版本,稍好一点,其书面版本中,您可以看到各种有效的方法来初始化并分配给new_msg = "New Random Char is "+static_cast <char> (random);
以获得所需的内容。再次注意删除std::string
是因为lck.unlock();
是RAII对象,它将在std::unique_lock
被销毁时释放mutex
范围的退出原样:
while
输出:
void consumer() {
while (true) {
unique_lock<mutex> lck{ mmutex };
mcond.wait(lck);
string new_string;
if (!mqueue.empty()) {
string m = mqueue.front();
mqueue.pop();
new_string = string("producer produced ") + m;
}
else
{
new_string = "producer has not produced yet ";
}
cout << new_string << endl;
//lck.unlock(); // <--- Not the intended usage of `unique_lock`
}
}
void producer() {
while (true) {
string new_msg("New Random Char is ");
unique_lock<mutex> lck{ mmutex };
int random = rand() % 40 + 40;
new_msg += static_cast<char>(random);
mqueue.push(new_msg);
mcond.notify_one();
}
}
答案 1 :(得分:1)
此代码的格式不正确。如果在调试器中运行它,您会很快找到它停止的原因,即....
string new_msg = NULL;
这是一种访问冲突,其中读取0(NULL
)处的字节以获取字符串。
已更正:
string new_msg; // default value is empty.
删除该代码后,需要进行一些必要的更改以使代码更接近预期的行为。
new_msg = "New Random Char is "+static_cast <char> (random);
这不起作用,因为它需要字符串的地址,并向其添加40到80个字节。从字符串移到某个“随机位置”。原始的C兼容性在这里受到了打击,并且(我认为)要实现的预期正确方法是....
new_msg = string("New Random Char is ") +static_cast <char> (random);
当转换为std::string
时,+现在可以作为追加运算符。
最后在消费者中……
string new_string = "producer produced " + m;
需要成为
new_string = "producer produced " + m;
否则,用于表示结果的变量new_string与读取队列的变量不同。
最后,在我的测试中,消费者跟不上生产者,并且需要某种形式的节流和终止条件。