我使用TBB来多线程我的应用程序的一部分。
以下代码在逻辑上负责非确定性行为:
std::mt19937 engine;
std::uniform_real_distribution<double> distribution(-1., 1.);
double x[N];
tbb::parallel_for(0, N, [&](int i)
{
// ... complicated stuff done in this loop
x[i] = distribution(engine);
});
我修改了代码,使用TBB TLS为每个线程使用一个PRNG,并使用循环索引为PRNG提供种子。
它似乎工作,但看起来奇怪的我。这是常见的做法吗?
tbb::enumerable_thread_specific<std::mt19937> engine;
std::uniform_real_distribution<double> distribution(-1., 1.);
double x[N];
tbb::parallel_for(0, N, [&](int i)
{
// ... complicated stuff done in this loop
engine.local().seed(i);
x[i] = distribution(engine.local());
});
我没有使用这个特定的并行化库。但是对于多线程,
- 必须阅读你使用的函数的文档,它们通常不是线程安全的,除非它明确声明它是线程安全的。
- 保护数据不受并发访问。例如通过互斥锁或线程yield构造。
下面是一个使用互斥锁/lock
的例子static std::mt19937 engine(std::random_device{}());
std::uniform_real_distribution<double> distribution(-1., 1.);
std::mutex mtx;
double x[N];
tbb::parallel_for(0, N, [&](int i)
{
// ... complicated stuff done in this loop
// extra scope to manage lifetime of lock
{
std::unique_lock<std::mutex> lock(mtx);
x[i] = distribution(engine);
}
});
也许你必须为引擎种子做一些类似的事情,这也可能不是线程安全的。