【问题标题】:Good way to code if (var=x) {var=y} atomicly?if (var=x) {var=y} 原子编码的好方法?
【发布时间】:2021-02-08 07:49:23
【问题描述】:

给定这个函数:

#include <mutex>

std::mutex mut;
bool data_being_processed=false;


void process_data() {
    std::lock_guard<std::mutex> lock(mut);

    if (data_being_processed == false) {
        data_being_processed = true;

        // Process data

        data_being_processed = false;
    }
}

我的理解是 process_data 不会被多个线程同时执行。但是它有效率吗? if (var=x) {var=y} 原子有没有更好的方法?

【问题讨论】:

  • 考虑将data_being_processed 设为原子值,或std::condition_variable
  • 您的互斥锁应该已经锁定,因此没有其他线程可以执行相同的过程。没有理由额外检查。那就是“互斥”代表:“互斥”

标签: c++ concurrency


【解决方案1】:

std::atomic 让这变得相当容易:

#include <atomic>

std::atomic<bool> data_being_processed{false};

void process_data() {
    bool value = false;
    if (data_being_processed.compare_exchange_weak(value, true)) {
        // Process data
        data_being_processed = false;
    }
}

compare_exchange_weakdata_being_processed 设置为true 如果它当前匹配value (false),如果它匹配并设置它返回的值true 否则它设置valuetrue并返回false

【讨论】:

    【解决方案2】:

    我的理解是process_data不会被多个线程同时执行。

    没错。

    它有效率吗? if (var=x) {var=y} 原子有没有更好的方法?

    使用std::atomic&lt;bool&gt;std::atomic_flag 可以更有效地完成该部分。

    例子:

    #include <atomic>
    
    void process_data() {
        static std::atomic_flag data_being_processed = ATOMIC_FLAG_INIT;
    
        if(not data_being_processed.test_and_set()) {
    
            std::cout << "processing data\n";
    
            data_being_processed.clear();
        } else {
            std::cout << "data is already being processed\n";
        }
    }
    

    但是,这会改变程序流程。在您的原始代码中,进入函数的第二个线程将等待,直到可以获取锁,在我的示例中,它会简单地跳过处理数据。

    【讨论】:

      【解决方案3】:

      我想详细说明我的评论。如前所述,“互斥”代表“互斥”。这意味着当互斥锁被锁定时,没有其他进程可以使用它。所有其他调用者都必须等到互斥锁解锁。示例:

      #include<mutex>
      #include<iostream>
      #include<chrono>
      #include<thread>
      
      static std::mutex mut;
      
      void process_data(int i) {
          std::scoped_lock lock{mut};
          std::cout << "start " << i << "...";
          std::this_thread::sleep_for(std::chrono::seconds(1));
          std::cout << "end " << i << '\n';
      }
      
      int main() {
          std::thread t1(process_data, 1);
          std::thread t2(process_data, 2);
          std::thread t3(process_data, 3);
          t1.join();
          t2.join();
          t3.join();
      }
      

      将返回(例如)

      start 1...end 1
      start 3...end 3
      start 2...end 2
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-24
        • 2016-02-26
        • 2013-01-28
        • 2011-10-31
        相关资源
        最近更新 更多