【发布时间】:2011-06-15 06:16:42
【问题描述】:
我在 C 中编码(实际上是在 OOC 中,然后编译为 C)。
如何指示线程在特定检查点等待,直到其他线程告诉它继续?
我实际上在线程中使用了一个紧密循环并轮询我从主线程更改的变量,但我认为这不是很好,对吧?除此之外,当我在线程中执行紧密循环时,是否应该在循环中包含睡眠以避免仅循环消耗大量 CPU 功率?
【问题讨论】:
标签: c multithreading pthreads
我在 C 中编码(实际上是在 OOC 中,然后编译为 C)。
如何指示线程在特定检查点等待,直到其他线程告诉它继续?
我实际上在线程中使用了一个紧密循环并轮询我从主线程更改的变量,但我认为这不是很好,对吧?除此之外,当我在线程中执行紧密循环时,是否应该在循环中包含睡眠以避免仅循环消耗大量 CPU 功率?
【问题讨论】:
标签: c multithreading pthreads
您似乎正在寻找pthread_cond_wait及其相关功能。
这里引用了manpage 的一个例子:
考虑两个共享变量 x 和 y,受互斥体 mut 保护,以及一个条件变量 cond,只要 x 大于 y,就会发出信号。
int x,y; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER;等到 x 大于 y 执行如下:
pthread_mutex_lock(&mut); while (x <= y) { pthread_cond_wait(&cond, &mut); } /* operate on x and y */ pthread_mutex_unlock(&mut);如果需要,对 x 和 y 的修改可能导致 x 变得大于 y 应该发出条件信号:
pthread_mutex_lock(&mut); /* modify x and y */ if (x > y) pthread_cond_broadcast(&cond); pthread_mutex_unlock(&mut);
最后它会按照您的要求执行:调用pthread_cond_wait(&cond) 的线程被阻塞,直到另一个线程(例如您的主线程)调用pthread_cond_broadcast(&cond)。在此期间,它只是处于blocked 状态,不消耗 CPU 周期。
【讨论】:
while() 循环进行循环,如示例中所示,因为您可能会在条件不正确的情况下被唤醒。
我认为这是一个很好的候选条件。线程应该等待一个条件,而另一个线程应该发出信号让这个线程继续。
您可以查找 pthread_cond_init ,这应该会导致其他功能
【讨论】:
您应该研究适当的同步原语,例如互斥锁、条件变量和信号量。在这种情况下,听起来condition variable 是 pthreads 库中最合适的工具。
【讨论】:
只是为了让您知道发生了什么,“紧密循环”会消耗您线程的 CPU 分配,就像您的线程执行的任何其他代码一样。唯一的区别是它什么也没做。好吧,我想让内核变热是一件很重要的事情......你可能永远不想这样做,除非你关心上下文切换的成本并且你知道肯定等待时间会很长比您线程的时间片短,大约为 1 毫秒。我不知道 sleep 是否和 yield 一样糟糕(AFAIK yield 将您的线程设置在线程列表的后面,以您的优先级激活),但两者都至少会导致上下文切换的惩罚。上下文切换是有代价的。上下文切换是线程的时间片结束时发生的事情。它可能会因为您以 yield 或 sleep 结束它而结束,或者如果内核通过抢占您来结束它。阅读有关 SMP 和自旋锁的信息,以了解有关上下文切换和适用紧密循环的情况的更多信息。
另外,当你睡觉时,你不知道你什么时候会再次醒来。所以你可能不想睡觉的一个原因是你需要快速完成一些事情。在重新安排之前,您可以等待几毫秒。
其他人都给了你 pthread_cond_wait 解决方案,它需要通过互斥锁进行锁定,看起来简单明了。性能可能足以满足您的需求,但与使用信号的解决方案相比相对较慢 (sigwait and pthread_kill)。复杂性会偷偷摸摸。
这里没有讨论为什么在测试之前锁定互斥锁是否需要等待条件。原因是这样的代码有一个缺陷:
while (x <= y) {
pthread_cond_wait(&cond, &mut);
}
您的线程可以测试( X
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mut);
这可能意味着您在许多不同的地方添加了这些互斥锁,因此您的代码变得更加复杂和缓慢。挂起线程等待条件的可能性始终存在。循环、测试、睡眠解决方案没有这些问题。因此,如果已知等待时间很短,那么在循环中使用 sleep 可能是一个很好的解决方案。特别是如果您可以在两次测试之间睡一秒钟或更长时间。如果可以,请不要为互斥锁和条件而烦恼。如果睡眠时间很短,比如 1 毫秒,而等待时间很长,比如几分钟或几小时,那么你最终会因为不断地醒来并重新进入睡眠状态而浪费一些资源。你必须判断。
还要注意,有时内核会尝试立即唤醒等待者线程,而其他时候会有延迟。如果线程唤醒得太快,它将在互斥锁被锁定时唤醒,并立即回到睡眠状态,直到互斥锁解锁。如果这成为问题,请以这种方式发出信号:
pthread_mutex_lock(&mut);
/* modify x and y */
if (x > y) {
pthread_mutex_unlock(&mut);
pthread_cond_broadcast(&cond);
} else
pthread_mutex_unlock(&mut);
感谢 user576875,我复制了他的代码示例。
【讨论】: