当前位置: 首页 > 知识库问答 >
问题:

为什么一个空的time循环的反应与一个有东西在里面的time循环不一样?

端木震博
2023-03-14

我目前有2个pthread正在运行,我想等待其中一个结束,以便我的程序继续运行。

在我的pthreads中,我有一个可以为真或假的变量(它是一个全局变量)。创建线程后(一个在cin中请求输入,一个等待10秒,如果达到10秒,它会杀死“cin”线程并结束自己,如果检测到cin,“cin”线程会杀死“计时器”线程),我希望我的程序等待。当每个线程结束时,它们将变量“stoptimer”置为真。

首先,在创建线程之后,我开始编写一个while循环,如下所示:

while(stoptimer==false){}

线程开始时,我们进入while循环,但即使线程结束并且“stOptimer”变为true,我们也不会退出循环。

我目前正在这样做:

rc = pthread_create(&threads[1], NULL, Timer, (void *)&td[1]);
if (rc) {
    cout << "Error:unable to create thread," << rc << endl;
    exit(-1);
}

rc = pthread_create(&threads[2], NULL, Choix, (void *)&i);
if (rc) {
    cout << "Error:unable to create thread," << rc << endl;
    exit(-1);
}

while (stoptimer==false) {
    cout<<"wait"<<endl;
}

在这里,您可以看到我正在创建线程,然后进入带有某些内容的time循环。如果我保持这个循环不变,它正在做我想要的事情,当计时器结束或用户输入一个值时,我们会退出,因为“stOptimer”不再是false。但我不希望这个cout在这里。

我尝试在循环中放置一个注释,以便它不是空的,但它仍然反应为空。在我的理解中,如果它与计数一起工作,那么现在它应该工作,但什么都不做。

它为什么要这样做?空while循环有什么特别之处吗?

共有2个答案

伊富
2023-03-14

问题不在于while循环。问题是你有一个未定义行为的竞争条件。具体来说,不允许同时从不同的线程中读取和写入一个变量(R/R可以,R/W和W/W不行)。编译器可以自由地“优化”while循环,方法是将< code>stoptimer的值缓存在寄存器中,并从寄存器而不是变量中读取。因此它不知道值是否改变了。允许编译器这样做是因为在while循环中读取< code>stoptimer时更改它是非法的。

要解决这个问题,您需要在读取和写入共享变量之前锁定互斥锁。所以你会做这样的事情:

while(true){
    pthread_mutex_lock(stoptimer_mutex);
    auto ts = stoptimer;
    pthread_mutex_unlock(stoptimer_mutex);
    if (ts==false)
        break;
}

现在这真的很长很乏味,你真的不想每次访问< code>stoptimer时都这样做。为了摆脱所有的手动锁定,您可以使用< code >原子

std::promise one_thread_done;
auto one_thread_future = one_thread_done.get_future();
std::thread timer_thread{Timer, td[1]}; //create threads
std::thread choix_thread{Choix, i};
one_thread_future.wait(); //wait until one of them is done

在每个线程中,您将函数放入<code>中,其中一个是thread_done。set_value()表示它已在try/catch中完成,因为如果另一个线程已经设置了它,它将抛出future_error

未来的好处是它们易于使用和理解。缺点是它们只有1次使用,没有重置未来的s。如果需要重复等待其中一个线程,则需要一个条件变量。

云远
2023-03-14

这里的问题是,您正在读取停止计时器变量而没有任何形式的线程同步,我怀疑您也没有在没有任何线程同步的情况下写入它。

为了保证一个线程所做的更改在另一个线程上可见,您必须使用某种形式的线程同步,或者依赖于了解底层cpu的内存模型(弱或强),这通常看起来很容易,但在最好的时候可能很难正确。

看看你的代码,我怀疑使用条件变量来跨线程同步会更明智。

 类似资料:
  • 我有一个循环,不断从我的串行端口读取。循环是无限的,所以我所知道的停止程序的唯一方法是使用。这个解决方案的问题是,当我使用时,我的程序会突然结束,我怀疑这也会导致其他问题。在程序结束时,我关闭了与我正在访问的串行端口的文件描述符的连接,但是我认为我的程序从来没有达到这个连接,因为我使用了命令,它只是在正确的位置停止程序它是。 有没有一种方法可以让我创建无限的time循环,并在我想要的时候退出,但同

  • 当我输入一个字符串运算符时,无论是加法()、减法(-)、乘法(*)、除法(/)还是模块(%),即使我输入了一个有效的输入,它仍然会进入而循环。我不知道问题可能是什么,因为当循环工作正常时,我必须为变量Num2输入一个int值。

  • 问题内容: 我想做的是请用户输入一些字符串以读入数组,然后要求用户输入该数量的字符串并将其读入数组。当我运行此代码时,它从不要求我在第一个for循环的第一个循环中输入内容,只打印出“字符串#0:字符串#1:”,然后我就可以输入文本了。为什么会这样,我做错了什么? 问题答案: 缓冲。 输入输入数量时,不会在输入缓冲区中占用换行符的位置。在for循环的迭代0中,缓冲区中已经有一行输入,并且可以立即完成

  • 问题在代码的注释中,很抱歉,我认为它更整洁,因为流程很重要,我想。。。 //*这是来自Oracle:(https://docs.oracle.com/javase/6/docs/api/java/util/Scanner.html#hasNextInt()) ”hasNextInt 公共布尔值hasnetint() 如果此扫描仪输入中的下一个标记可以使用nextInt()方法解释为默认基数中的in

  • 我的程序中有两个while循环。第一个是针对游戏菜单的,第二个是针对实际游戏的。如果“Gameover-Event”发生,我想返回菜单。我不知道该怎么做。

  • 我正在构建一个gradebook来存储学生和教师,每个学生和教师都有一个唯一的ID,以及他们各自在Student和Teacher对象的ArrayList中注册或教学的类。我有文件夹路径“j:/compsci/类/”,为每个类存储一个文本文件。 文本文件格式: 第1行:班级名称、教师ID、期间、荣誉?、班级ID 第2行:班级中每个学生的学生ID(用逗号分隔)。 在这里,我初始化了每个学生正在接受的所