我对c ++中的多线程有疑问。我的情况如下
void ThreadedRead(int32_t thread_num, BinReader reader) {
while (!reader.endOfData) {
thread_buckets[thread_num].clear();
thread_buckets[thread_num] = reader.readnextbatch()
thread_flags[thread_num] = THREAD_WAITING;
while (thread_flags[thread_num] != THREAD_RUNNING) {
// wait until awakened
if (thread_flags[thread_num] != THREAD_RUNNING) {
//go back to sleep
}
}
}
thread_flags[thread_num] = THREAD_FINISHED;
}
以上代码的任何部分都不会写入或访问线程之间共享的内存。为每个线程分配一个thread_num和一个可用于读取数据的唯一读取器对象。
我希望主线程能够通知处于THREAD_WAITING状态的线程,他的状态已经变回THREAD_RUNNING并且他需要做一些工作。我不想让他继续投票他的状态。
我理解条件变量和互斥量可以帮助我。但我不确定如何使用它们,因为我不想获得或需要锁定。 mainthread blanket如何通知所有等待线程他们现在可以自由地读取更多数据?
编辑: 以防任何人需要更多细节
1)读者读取一些文件 2)thread_buckets是uint16向量的向量 3)threadflags是一个int向量
他们都已适当调整大小
答案 0 :(得分:3)
我意识到你写过你想要避免条件变量和锁。另一方面,你提到这是因为你不确定如何使用它们。请考虑以下示例以完成工作而不进行轮询:
条件变量的技巧是单个condition_variable
对象和单个mutex
对象将为您进行管理,包括处理工作线程中的unique_lock
个对象。由于您将问题标记为C ++,我假设您正在讨论C ++ 11(或更高版本)多线程(我猜C-pthreads可能会起作用)。您的代码如下:
// compile for C++11 or higher
#include <thread>
#include <condition_variable>
#include <mutex>
// objects visible to both master and workers:
std::condition_variable cvr;
std::mutex mtx;
void ThreadedRead(int32_t thread_num, BinReader reader) {
while (!reader.endOfData) {
thread_buckets[thread_num].clear();
thread_buckets[thread_num] = reader.readnextbatch()
std::unique_lock<std::mutex> myLock(mtx);
// This lock will be managed by the condition variable!
thread_flags[thread_num] = THREAD_WAITING;
while (thread_flags[thread_num] == THREAD_WAITING) {
cvr.wait(myLock);
// ...must be in a loop as shown because of potential spurious wake-ups
}
}
thread_flags[thread_num] = THREAD_FINISHED;
}
从主线程中(重新)激活工作人员:
{ // block...
// step 1: usually make sure that there is no worker still preparing itself at the moment
std::unique_lock<std::mutex> someLock(mtx);
// (in your case this would not cover workers currently busy with reader.readnextbatch(),
// these would be not re-started this time...)
// step 2: set all worker threads that should work now to THREAD_RUNNING
for (...looping over the worker's flags...) {
if (...corresponding worker should run now...) {
flag = THREAD_RUNNING;
}
}
// step 3: signalize the workers to run now
cvr.notify_all();
} // ...block, releasing someLock
注意:
.notify_one()
成员函数而不是.notify_all()
并考虑哪一个并不重要。另请注意,在这种情况下,单个互斥/条件变量对就足够了。atomic
对象中,例如全局std::atomic<int>
,或者可以更好地控制std::vector<std::atomic<int>>
。std::condition_variable
的一个很好的介绍也启发了建议的解决方案:cplusplus website 答案 1 :(得分:1)
看起来有一些问题。首先,你不需要循环中的条件:
while (thread_flags[thread_num] != THREAD_RUNNING);
将独立工作。只要该条件为假,循环就会退出。
如果您想要做的就是尽可能快地检查thread_flags,只需在循环中输入:
while (thread_flags[thread_num] != THREAD_RUNNING) yield(100);
这将导致线程产生CPU,以便在线程等待其状态发生变化时可以执行其他操作。这将使轮询的开销接近可忽略不计。您可以尝试睡眠持续时间以找到一个好的值。 100毫秒可能是偏长的。
根据导致线程状态发生变化的原因,您可以让线程轮询直接调用条件/值(仍处于休眠状态)并且根本不打扰状态。
这里有很多选择。如果你查阅读者线程,你可能会找到你想要的东西;有一个单独的读者线程是很常见的。