Multithreading 原子与变量传递参考in<;螺纹>;
我想写一个程序,其中,随机数将被创建,我将跟踪其中最大的。三个线程将并行运行 我用两种方法来做。首先我在main()中创建一个变量,然后通过ref.传递给每个线程。最后,此变量保存生成的最大值。当变量更新时,我使用互斥锁(我真的必须吗?) 第二种方法使用std::atomic并产生相同的结果(据我测试) 为了在我的项目中使用,这是一个很小的例子,所有线程都能看到所有线程找到的当前最佳值 守则:Multithreading 原子与变量传递参考in<;螺纹>;,multithreading,c++11,pthreads,shared-memory,atomic,Multithreading,C++11,Pthreads,Shared Memory,Atomic,我想写一个程序,其中,随机数将被创建,我将跟踪其中最大的。三个线程将并行运行 我用两种方法来做。首先我在main()中创建一个变量,然后通过ref.传递给每个线程。最后,此变量保存生成的最大值。当变量更新时,我使用互斥锁(我真的必须吗?) 第二种方法使用std::atomic并产生相同的结果(据我测试) 为了在我的项目中使用,这是一个很小的例子,所有线程都能看到所有线程找到的当前最佳值 守则: #include <iostream> // std::cout #inclu
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
#include <atomic>
#include <random>
std::default_random_engine generator((unsigned int)time(0));
int random(int n) {
std::uniform_int_distribution<int> distribution(0, n);
return distribution(generator);
}
std::mutex mtx; // mutex for critical section
std::atomic<int> at_best(0);
void update_cur_best(int& cur_best, int a, int b) {
// critical section (exclusive access to std::cout signaled by locking mtx):
if(cur_best > a && cur_best > b)
return;
if(at_best > a && at_best > b)
return;
int best;
if(a > b)
best = a;
else
best = b;
mtx.lock();
cur_best = best;
mtx.unlock();
// or
if(a > b)
at_best = a;
else
at_best = b;
}
void run(int max, int& best) {
for(int i = 0; i < 15; ++i) {
update_cur_best(best, random(max), random(max));
}
}
//g++ -std=c++0x -pthread px.cpp -o px
int main ()
{
int best = 0;
std::thread th1 (run, 100, std::ref(best));
std::thread th2 (run, 100, std::ref(best));
std::thread th3 (run, 100, std::ref(best));
th1.join();
th2.join();
th3.join();
std::cout << "best = " << best << std::endl;
std::cout << "at_best = " << at_best << std::endl;
return 0;
}
#包括//std::cout
#include//std::thread
#include//std::mutex
#包括:“原子
类型是封装有保证访问的值的类型
不引起数据竞争,可用于同步内存
不同线程之间的访问。”
它们在数量上相等吗
它们产生的结果和效率如何
如果是,那么为什么要引入原子?我应该用什么方法
使用?速度是我感兴趣的
有没有更快的方法来实现此功能
请记住,对于我的实际项目,重点是best
将从所有线程中获得当前最佳值,以便更容易进行比较。至于使用互斥体:您正在互斥体外部读取cur\u best
,并在保持互斥体的同时更新它-这是行不通的
使用原子学:
虽然读取或更新原子变量对于当前发生的事情来说是原子性的,但每个单独的读取或更新都是原子性的——原子性不适用于单独的表达式
因此,例如,if(at_best>a&&at_best>b)
中的表达式可能解析为true
(我忽略了at_best
在该表达式中的每次求值都可能返回不同的值的事实),在线程开始执行时:
if(a > b)
at_best = a;
else
at_best = b;
原子变量充其量
可能已被另一个线程更新,而这个线程可能正在用较小的值覆盖它。现在,由另一个线程设置的较大值将永远丢失。此外,在生成器
和分发版
上存在数据争用:标准随机数生成器和分发版不能由多个线程同时更新。通过为每个线程创建随机数生成器/分布,可以轻松解决此问题。您还需要确保全局“当前最大值”的比较和更新是原子的,例如,使用():
当且仅当当前值为cur\u best
时,它将best
的值更新为a
。否则,cur\u best
将更新为当前值best
,循环将重试。实际上,best
只有在其他线程在尝试更新之前没有将其设置为大于a
的值时才会更新。th1
可以写入best
(按住mtx
),而th2
读取best
(无需按住mtx
)。这是一种未定义行为的数据竞争。您需要将关键部分扩展到所有update\u cur\u best
。也就是说,将best
更改为atomic
将使互斥锁变得不必要并提高性能。因此,您认为应该选择atomic方法。如果是,请回答问题,以便获得完整答案@nwp.so,您的意思是这两种方法都是错误的。我应该如何解决这个问题?@G.Samaras请使用锁。当您想要执行“读取、比较、可能更新”操作时,获取锁,执行操作,然后释放它。如果您真正想要做的是让线程跟踪独立系列中的最大数量,那么让每个线程确定自己的最大数量(如果使用单独的RNG,则不需要与任何其他线程共享状态),然后每个线程都可以报告它的最大值。这也可以通过向线程传递一些对象来保存结果而不进行共享来完成。当线程被连接时,可以查询该对象以查看线程的最大值是否大于“全局”最大值。最终结果是每个线程在不干扰其他线程的情况下完成其工作,并且除了连接之外不需要同步。这也是我所想的。迈克尔所说的也很有趣。你看@MichaelBurr,我想把它用于我的实际项目。在问题中提出的问题中,你是对的。值得一试!我将不得不阅读一些关于记忆顺序的理论,并比较记忆交换的弱,但我了解了大局!谢谢
#include <iostream> // std::cout
#include <thread> // std::thread
#include <atomic>
#include <random>
#include <array>
void update_cur_best(std::atomic<int>& best, int a, int b) {
if (a < b) {
a = b;
}
auto cur_best = best.load(std::memory_order_relaxed);
while (cur_best < a && !best.compare_exchange_weak(cur_best, a))
;
}
void run(int max, std::atomic<int>& best) {
std::mt19937 generator{std::random_device{}()};
std::uniform_int_distribution<int> distribution{0, max};
for(int i = 0; i < 15; ++i) {
update_cur_best(best, distribution(generator), distribution(generator));
}
}
//g++ -std=c++0x -pthread px.cpp -o px
int main()
{
std::atomic<int> best{0};
const int max = 100;
std::array<std::thread, 3> threads;
for (auto& t : threads) {
t = std::thread(run, max, std::ref(best));
}
for (auto& t : threads) {
t.join();
}
std::cout << "best = " << best << std::endl;
}
auto cur_best = best.load(std::memory_order_relaxed);
while (cur_best < a && !best.compare_exchange_weak(cur_best, a))
;