简单的POSIX线程的问题

我有这个POSIX线程:

void subthread(void) { while(!quit_thread) { // do something ... // don't waste cpu cycles if(!quit_thread) usleep(500); } // free resources ... // tell main thread we're done quit_thread = FALSE; } 

现在我想从我的主线程中终止subthread()。 我已经尝试了以下内容:

 quit_thread = TRUE; // wait until subthread() has cleaned its resources while(quit_thread); 

但它不工作! while()子句永远不会退出,尽pipe我的子线程在释放其资源之后明确地将quit_thread设置为FALSE!

如果我修改我的关机代码,如下所示:

 quit_thread = TRUE; // wait until subthread() has cleaned its resources while(quit_thread) usleep(10); 

那么一切工作正常! 有人可以向我解释为什么第一个解决scheme不起作用,为什么有usleep(10)的版本突然起作用? 我知道这不是一个漂亮的解决scheme。 我可以使用信号/信号,但我想了解一些有关multithreading,所以我想知道为什么我的第一个解决scheme不起作用。

谢谢!

最有可能发生的事情是,你的编译器不知道quit_thread可以被另一个线程改变(因为C不知道线程,至少在问这个问题的时候)。 因此,它正在优化while循环到无限循环。

换句话说,它看起来在这个代码:

 quit_thread = TRUE; while(quit_thread); 

并认为自己,“哈,这个循环中的任何东西都不能将quit_thread改为FALSE,所以编码器显然只是为了写while (TRUE); ”。

当您将调用添加到usleep ,编译器会有另一个想法,并假定函数调用可能会更改全局,所以它会安全并且不会对其进行优化。

通常你会把变量标记为volatile来停止编译器优化它,但是在这种情况下,你应该使用pthreads提供的工具,并在将标志设置为true之后加入到线程中(并且没有子线程重置它,如果需要,在连接之后在主线程中执行)。 原因是一个连接可能比一个等待变量变化的连续循环更高效,因为执行连接的线程很可能不会被执行,直到连接需要完成为止。

在你的纺纱解决方案中,加入的线程很可能会继续运行,并吸取CPU咕噜声。

换句话说,做一些事情:

 Main thread Child thread ------------------- ------------------- fStop = false start Child Initialise Do some other stuff while not fStop: fStop = true Do what you have to do Finish up and exit join to Child Do yet more stuff 

另外,您应该从技术上保护互斥变量的共享变量,但这是少数情况下可以使用的单向通信,其中变量的半值变化无关紧要(false / not-false)。

通常互斥保护一个变量的原因是阻止一个线程在半改变状态下看到它。 假设你有一个两字节的整数来计算一些对象的数量,它被设置为0x00ff (255)。

让我们进一步说,线程A试图增加计数,但它不是一个原子操作。 它将顶部字节更改为0x01但在底部字节更改为0x00 ,线程B 0x01ff并将其读取为0x01ff

现在,如果线程B想要对由该值计算的最后一个元素进行操作,那么这不会很好。 它应该看0x0100而不是试图看看0x01ff ,如果不是灾难性的,其效果将是错误的。

如果count变量受到一个互斥体的保护,那么线程B在线程A完成更新之前不会查看它,因此不会发生任何问题。

与单向布尔值无关的原因是因为任何半状态也将被视为真或假,因此,如果线程A在将0x0000转换为0x0001 (只是顶部字节)之间的中途,线程B仍然会看到作为0x0000 (false)并继续(直到线程A下一次完成更新)。

如果线程A将布尔值转换为0xffff ,则线程B仍然认为0xff00的半状态为真,所以在线程A完成更新布尔值之前它将完成它的工作。

这两种可能性都不是简单的,因为在这两种情况下,线程A都在改变布尔值,最终会结束。 B线程早一点还是稍后一点点检测到它并不重要。

没有内存围栏 ,不能保证在一个线程中写入的值将出现在另一个线程中。 大多数pthread基元引入了一个障碍,像usleep这样的几个系统调用也是如此。 在读取和写入周围使用互斥锁引入了障碍,更一般地说,防止在部分写入状态下看到多字节值。

您还需要分开让线程停止执行的想法,并报告已经停止,并且似乎对两者都使用相同的变量。

while(quite_thread); 正在使用的值quit_thread被设置在它之前的行上。 调用函数( usleep )会导致编译器重新加载每个测试的值。

无论如何,这是等待线程完成的错误方法。 改用pthread_join

你正在“学习”多错的方式。 正确的方法是学习使用互斥锁和条件变量; 任何其他解决方案在某些情况下将失败。