【问题标题】:Operations done in one thread visible to another without explicit synchronization在一个线程中完成的操作对另一个线程可见,无需显式同步
【发布时间】:2020-12-15 12:53:26
【问题描述】:

我的问题是关于线程同步的。请看下面的代码:

std::vector<int> v_int;

for (size_t i = 0; i < 5; ++i) {
    v_int.emplace_back(i);
}

auto f_async = std::async(std::launch::async,
    [](auto v_int) mutable {
        for (auto& el : v_int.get()) {
            el += 10;
        }
    }, std::ref(v_int));

//more instructions...

f_async.get();

我的问题是 std::async 产生的新线程如何“看到”(主)线程对向量所做的修改,因为没有获取释放(互斥锁, atomic bool, atomic flag...) 来保护向量?

鉴于新线程在完全写入向量后“发生”,是否存在隐式顺序一致性?

典型的生产者/消费者应该是这样的:

std::vector<int> v_int_global;
std::atomic<bool> data_ready{ false };

void producer_int() {
    for (size_t i = 0; i < 5; ++i) {
        v_int_global.emplace_back(i);
    }
    data_ready.store(true, std::memory_order_release);
}

void transformer_int() {
    while (!data_ready.load(std::memory_order_acquire));
    for (auto& el : v_int_global) {
        el += 10;
    }
}

int main() {
    std::thread t1 (producer_int);
    std::thread t2 (transformer_int);

    t1.join();
    t2.join();
}

谢谢。

【问题讨论】:

  • en.cppreference.com/w/cpp/thread/async - 请参阅关于 synchronizes-with 的部分。虽然我没有标准可以验证它。
  • “考虑到新线程在完全写入向量后“发生”,是否存在隐式顺序一致性?” - 在您给出的示例中,是的。在这里,您启动异步任务,然后立即在返回的未来调用 .get,这有效地使整个示例同步。如果您要将填充v_int 的代码移动到std::async 的调用和对f_async.get 的调用之间,您将拥有UB。

标签: c++ multithreading asynchronous language-lawyer


【解决方案1】:

std::async 被指定为与参数的调用同步([futures.async]/p5):

同步:无论提供何种策略参数,

(5.1) 调用asyncsynchronizes with 调用f[ 注意:即使对应的未来 对象被移动到另一个线程。 — 尾注 ];和

(5.2)函数f的完成顺序排在前面 ([intro.multithread]) 共享状态已准备就绪。 [ 注意: f 可能 根本不会被调用,所以它的完成可能永远不会发生。 — 结束 注意 ]

synchronizes-with 一词意味着至少会发生一个“获取-发布”事件。因此,在调用 std::async 之前完成的任何工作都保证对 lambda 可见,无论何时执行。

同样,future::get() 与将结果存储在共享状态 ([futures.state]/p9) 的调用同步:

对成功设置共享状态的存储结果的函数的调用与对成功检测由该设置产生的就绪状态的函数的调用同步。将结果(无论是正常的还是异常的)存储到共享状态中与从共享状态上的等待函数的调用成功返回同步。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    相关资源
    最近更新 更多