带有计时器的C++多线程编程

Lon*_*Lin 2 c++ multithreading timer

我是多线程编程的新手,所以这个问题可能看起来有点傻,但我真的需要解决这个问题,所以我可以将它应用到我的项目中(这更复杂).跟随是我的代码,我试图让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;
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*phe 6

多进程

您的代码是多进程而不是多线程: fork()将通过复制调用进程来创建一个新的单独进程.

结果:在复制时,所有变量在两个进程中都包含相同的值.但是每个进程都有自己的副本,因此父进程中修改的变量不会在子地址空间中更新,反之亦然.

如果你想在进程之间共享变量,你应该看看这个SO问题

多线程

对于真正的多线程,你应该使用std::thread.忘记volatile,因为它不是线程安全的.请<atomic>改用,正如这部精彩视频中所解释的那样.

这是第一次尝试:

#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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要使用互斥锁来保护原子访问,如果您愿意,lock_guard建议您使用互斥锁.

这个例子当然相当弱,因为如果你测试一个原子变量if if-condition,那么当输入if-block时它的值可能已经改变了.这不会在您的逻辑中导致"完成"意味着"完成"的问题.但是,如果你需要更加苛刻的方法,
compare_exchange_weak()或者compare_exchange_strong()可以进一步提供帮助.