我对互斥锁有些麻烦,请考虑这个例子:
boost::mutex m;
void thread1_unstack(std::stack<std::string>& msg) {
while (true) {
if (msg.empty()) continue;
m.lock();
std::string msg_string = msg.top();
msg.pop();
std::cout << msg_string << std::endl;
m.unlock();
}
}
void thread2_stack(std::stack& msg) {
while (1) {
msg.push("very long message");
}
}
void wait_for_finish(std::stack& msg) {
while (!msg.empty()) sleep(1);
}
int main() {
std::stack<std::string> msg;
boost::thread t1 = boost::thread(boost::bind(&thread1_unstack, boost::ref(msg));
boost::thread t2 = boost::thread(boost::bind(&thread2_stack, boost::ref(msg));
wait_for_finish(msg);
t1.stop();
t2.stop();
}
所以问题在于wait_for_finish函数。当调用msg.pop()时,函数检测到堆栈是空的,因此线程在juste之后被停止,有时,消息(std :: cout)没有完全打印在屏幕上。
所以我想&#34;锁定&#34; msg变量为3行:
std::string msg_string = msg.top();
msg.pop();
std::cout << msg_string << std::endl;
像那样,wait_for_finish在std :: cout期间没有检测到堆栈是空的。
我试图锁定一个boost :: mutex并在最后解锁它,但没有任何改变。
所以我不知道如何解决它
答案 0 :(得分:1)
您必须使用互斥锁保护所有访问权限:
boost::mutex m;
void thread1_unstack(std::stack<std::string>& msg) {
while (true) {
m.lock();
bool msgEmpty = msg.empty();
m.unlock();
if (msgEmpty) continue;
m.lock();
std::string msg_string = msg.top();
msg.pop();
std::cout << msg_string << std::endl;
m.unlock();
}
}
void thread2_stack(std::stack& msg) {
while (1) {
m.lock();
msg.push("very long message");
m.unlock();
}
}
void wait_for_finish(std::stack& msg) {
while(true) {
m.lock();
bool msgEmpty = msg.empty();
m.unlock();
if(msgEmpty) break;
sleep(1);
}
}
int main() {
std::stack<std::string> msg;
boost::thread t1 = boost::thread(boost::bind(&thread1_unstack, boost::ref(msg));
boost::thread t2 = boost::thread(boost::bind(&thread2_stack, boost::ref(msg));
wait_for_finish(msg);
t1.stop();
t2.stop();
}
答案 1 :(得分:0)
我们的讨论中的评论显示您正在使用某种线程安全的可等待容器。你需要通过它的合作来停止线程,以确保它有时间完成它应该对最后一个对象做的任何工作。我会建议这种方法:
拥有一个stop
标志,该标志是原子的或受互斥锁保护。它应该开始清除。
当线程从容器中获取对象时,在打印它之前,它会检查stop
标志。如果设置了标志,则线程终止。
如果要停止线程,请设置stop
标志,向容器添加虚拟对象,然后加入线程。
虚拟对象解除阻塞线程,并且它不会被打印,因为线程不会在设置stop
标志的情况下打印。通过join
线程,您可以确保它在您终止之前完成了它必须完成的所有工作。
你也可以使用&#34;死亡对象&#34;做法。例如,假设您的代码无法排空空字符串 - 您可以使用空字符串作为死亡对象&#34;。它的工作原理如下:
当您从容器中获取对象时,请检查它是否为死亡对象。如果是,请终止。
要使线程终止,请将死亡对象排队,然后加入该线程。
这有相同的行为。对死亡对象进行排队会解除对线程的阻塞(因为容器不再是空的,只有在它被阻塞时才会阻塞),并保证线程在完成后终止(因为线程一旦将其取消就会检查)。加入线程可确保它在死亡对象之前完全处理完所有对象。