C++ C++;带定时器的多线程编程

C++ C++;带定时器的多线程编程,c++,multithreading,timer,C++,Multithreading,Timer,我是多线程编程新手,所以这个问题可能看起来有点傻,但我真的需要解决这个问题,这样我才能将它应用到我的项目中(这要复杂得多)。 下面是我的代码,我试图让两个线程(父线程和子线程)在执行时更新同一个共享计时器,并在计时器达到特定限制时停止。 但当我编译并执行下面这段代码时,有两种不同的结果:1。child打印“由child在200000完成”,但程序不退出;2.在child打印“由child在200000完成”并退出后,parent继续执行,打印几十行“parent doing work”和“par

我是多线程编程新手,所以这个问题可能看起来有点傻,但我真的需要解决这个问题,这样我才能将它应用到我的项目中(这要复杂得多)。 下面是我的代码,我试图让两个线程(父线程和子线程)在执行时更新同一个共享计时器,并在计时器达到特定限制时停止。 但当我编译并执行下面这段代码时,有两种不同的结果:1。child打印“由child在200000完成”,但程序不退出;2.在child打印“由child在200000完成”并退出后,parent继续执行,打印几十行“parent doing work”和“parent at 190000”,然后打印“done by parent at 200000”,程序正确退出。 我想要的行为是,无论哪个线程更新计时器、达到限制并退出,另一个线程都应该停止执行并退出。我想我可能在这里遗漏了一些琐碎的东西,但我已经尝试了很多方法来更改代码,但我尝试的方法似乎都不管用。任何帮助都将不胜感激:)

#包括
#包括
#包括
#包括
使用名称空间std;
互斥mtx;
int main(){
int rc;
volatile int done=0;
时钟启动=时钟();
现在不稳定的时钟;
rc=fork();
如果(rc==0){//child
while(true){

cout多进程

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

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

如果你想在进程之间共享变量,你应该看看

多线程

对于真正的多线程,您应该使用
std::thread
。忘记volatile,因为它不是线程安全的。请改用volatile,如本文所述

这里是第一次尝试:

#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;
}
#包括
#包括
#包括
#包括将是推荐的替代方案

这个例子当然很弱,因为如果你测试一个原子变量的if条件,它的值在进入if块时可能已经改变了。这不会在你的逻辑中造成问题,因为“完成”意味着“完成”。但是如果你需要更谨慎的方法,

或者可以进一步帮助。

volatile
并没有像您认为的那样使用std::atomic。而且您不是在测试线程而是进程-
fork
创建一个新进程,而不是进程中的新线程。您没有两个线程,而是一个父进程和一个子进程(这完全不同)。请停止使用
volatile
。对于
fork
和进程,您可以为IPC阅读。这些不是独立的线程,而是独立的进程。@LongLin为什么不使用
std::thread
?谢谢您的示例。我在阅读上述评论后不久就让它工作了,我记得贴了一条评论。无论如何,我还有一个后续问题。我的解决方案与你的非常相似。首先,在main()中,我把父行放在子行的前面,输出结果表明父行总是先执行,子行只在父行完成后执行;然后我交换了这两行,结果正如预期的那样。那么,围绕这两行的交换是否真的会像我提到的那样影响执行顺序?如果是,为什么?谢谢e:)您始终至少有一个执行的线程:主线程。它按顺序执行语句,因此,如果遇到对父线程的调用,它将执行该函数调用。只有在创建和启动线程对象时,decond线程才会并行执行(尽可能)。因此,如果您创建此对象,使用第一个顺序,则当第二个线程启动时,父线程必须结束。主线程将礼貌地等待连接发生。使用另一个顺序,第二个线程启动,并在主线程执行父线程时执行子线程。我的注释是日志,但尝试制作一个序列图我想它会变得更清晰
#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;
}