C ++并发中的内存可见性(无数据争用) [英] Memory visibility in C++ concurrency (no data race)

查看:231
本文介绍了C ++并发中的内存可见性(无数据争用)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是 c ++中的Shared_ptr和内存可见性这个问题更多的是关于内存可见性,而不是数据竞争.

This question is more about memory visibility rather than data race.

在Java中,我有:

ExecutorService executor = Executors.newSingleThreadExecutor();
Integer i = new Integer(5); // no write to i afterwards
executor.submit(() -> {
    System.out.println(i);
});

我认为这不是线程安全的.由于不需要将值5放入主内存中,因此它可以保留在主线程的CPU缓存中.由于没有内存障碍,因此无法保证执行程序线程看到值5.要确保该值位于主内存中,请使用同步或AtomicInteger或volatile int.

I don't think this is thread-safe. Because there is no need to put value 5 in the main memory, it could stay in the main thread's CPU cache. Since there is no memory barrier, the executor thread is not guaranteed to see the value 5. To make sure the value is in the main memory, you either use synchronization, or use AtomicInteger, or volatile int.

如果您使用C ++中的shared_ptr做类似的事情,那么安全吗?

If you do something similar with shared_ptr in C++, is it safe?

auto sp = std::make_shared<int>(5); // no write to the int afterwards
myExecutor.submit([sp](){
    std::cout << sp;
});

执行程序线程是否保证可以看到值5?请注意,shared_ptr被复制到lambda,而不是int.

Is the executor thread guaranteed to see the value 5? Note that the shared_ptr is copied to the lambda, not the int.

这是一个更完整的示例:

Here is a more complete example:

假设我有一个主线程和辅助线程.在主线程中,我构造了shared_ptr<Object>并将shared_ptr复制到工作线程,如果Object类中根本没有同步,则可以安全地使用shared_ptr的副本(不写入对象)施工后)?

Suppose I have a main thread and worker thread. In main thread I've constructed a shared_ptr<Object> and copy the shared_ptr to the worker thread, is this safe to use the copy of the shared_ptr if there is no synchronization in Object class at all (NO write to the object after construction)?

我的主要难题是,对象是在堆的主线程中构造的,shared_ptr是复制的,而不是对象.工作线程是否肯定具有对象的内存可见性?

My main puzzle is, the Object is constructed in main thread on the heap, the shared_ptr is copied but not the Object. Will the worker thread definitely have the memory visibility of the Object? Would it be possible that the value of Object is actually in main thread's CPU cache and not in the main memory?

struct WorkingQueue{
    WorkingQueue()=default;

    void push(std::function<void()> task){
        std::lock_guard<std::mutex> lock{mutex};
        queue.push(std::move(task));
    }

    std::optional<std::function<void()>> popIfNotEmpty(){
        std::lock_guard<std::mutex> lock{mutex};
        if(queue.empty()){
            return std::nullopt;
        }
        auto task = queue.front();
        queue.pop();
        return task;
    }

    bool empty(){
        std::lock_guard<std::mutex> lock{mutex};
        return queue.empty();
    }

    mutable std::mutex mutex;
    std::queue<std::function<void()>> queue;
};

int main(){
    WorkingQueue queue;
    std::atomic<bool> stopFlag{false};
    auto f = std::async(std::launch::async, [&queue, &stopFlag](){
        while(!stopFlag || !queue.empty()){
            auto task = queue.popIfNotEmpty();
            if(task){
                (*task)();
            }
        }
    });
    auto sp = std::make_shared<int>(5);
    queue.push([sp](){
        std::cout << *sp;
    });

    stopFlag = true;
    f.get();
}

这个程序员能保证输出5吗?

Is this programmer guaranteed to output 5?

推荐答案

如果在Object类中根本没有同步,

这样可以安全地使用shared_ptr的副本

is this safe to use the copy of the shared_ptr if there is no synchronization in Object class at all

是的,std::shared_ptr是同步的,因此它的引用计数是线程安全的.它所指向的对象的读/写同步取决于您.

Yes, std::shared_ptr is synchronized so that it's reference count is thread safe. Read/write synchronization of the object it points to, however, is up to you.

在问题编辑后进行

执行程序线程是否保证看到值5?

Is the executor thread guaranteed to see the value 5?

否,这与将原始指针传递到myExecutor线程完全相同.

No, this is exactly the same as passing a raw pointer to your myExecutor thread.

这篇关于C ++并发中的内存可见性(无数据争用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆