我是多线程编程的新手,所以这个问题可能看起来有点傻,但我真的需要解决这个问题,所以我可以将它应用到我的项目中(这更复杂)。 跟随是我的代码,我试图让2个线程(父和子)更新相同的共享计时器,并在计时器达到特定限制时停止。 但是当我编译并执行这段代码时,有两种不同的结果:1。子打印“由孩子在200000完成”,但程序没有退出; 2.孩子打印“孩子在200000完成”并退出后,父母继续执行,打印几十行“父母做工作”和“父母在190000”,然后打印“父母在200000完成”和程序退出正常。 我想要的行为是更新计时器的任何线程,达到限制并退出,另一个线程应该停止执行并退出。我想我可能会在这里遗漏一些微不足道的东西,但我尝试过以多种方式更改代码,而我尝试过的任何东西似乎都没有用。任何帮助将不胜感激:)
#include <iostream>
#include <unistd.h>
#include <mutex>
#include <time.h>
using namespace std;
mutex mtx;
int main () {
int rc;
volatile int done = 0;
clock_t start = clock();
volatile clock_t now;
rc = fork();
if (rc == 0) { //child
while (true) {
cout << "child doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
mtx.unlock();
break;
}
cout << "child at " << now << endl;
mtx.unlock();
}
_exit(0);
}
else { // parent
while (true) {
cout << "parent doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
mtx.unlock();
break;
}
cout << "parent at " << now << endl;
mtx.unlock();
}
}
return 0;
}
答案 0 :(得分:6)
<强>多进程强>
您的代码是多进程而不是多线程:fork()
将通过复制调用进程来创建一个新的单独进程。
结果:在复制时,所有变量在两个进程中都包含相同的值。但是每个进程都有自己的副本,因此父进程中修改的变量不会在子地址空间中更新,反之亦然。
如果您想在流程之间共享变量,请查看this SO question
<强>多线程强>
对于真正的多线程,您应该使用std::thread
。忘记volatile,因为它不是线程安全的。请改用<atomic>
,如awesome video中所述。
首先尝试:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <time.h>
using namespace std;
void child (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "child doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
}
cout << "child at " << now << endl;
this_thread::yield();
}
}
void parent (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "parent doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
}
cout << "parent at " << now << endl;
this_thread::yield();
}
}
int main () {
atomic<int> done{0};
clock_t start = clock();
atomic<clock_t> now;
thread t(child, std::ref(done), std::ref(now), start); // attention, without ref, you get clones
parent (done, now, start);
t.join();
return 0;
}
请注意,您不需要使用互斥锁保护原子访问,如果您想这样做,建议使用lock_guard
替代。
这个例子当然相当弱,因为如果你测试一个原子变量if if-condition,那么当输入if-block时它的值可能已经改变了。这不会在您的逻辑中导致“完成”意味着“完成”的问题。但如果你需要一个更加苛刻的方法,
compare_exchange_weak()
或compare_exchange_strong()
可能会有所帮助。