Multithreading 原子与变量传递参考in<;螺纹>;

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

我想写一个程序,其中,随机数将被创建,我将跟踪其中最大的。三个线程将并行运行

我用两种方法来做。首先我在main()中创建一个变量,然后通过ref.传递给每个线程。最后,此变量保存生成的最大值。当变量更新时,我使用互斥锁(我真的必须吗?)

第二种方法使用std::atomic并产生相同的结果(据我测试)

为了在我的项目中使用,这是一个很小的例子,所有线程都能看到所有线程找到的当前最佳值

守则:

#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))
        ;