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

时间:2016-03-17 20:06:33

标签: 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;
}

1 个答案:

答案 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()可能会有所帮助。