Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
803 views
in Technique[技术] by (71.8m points)

c++ - Is there an implicit memory barrier with synchronized-with relationship on thread::join?

I have a code at work that starts multiple threads that doing some operations and if any of them fail they set the shared variable to false.

Then main thread joins all the worker threads. Simulation of this looks roughly like this (I commented out the possible fix which I don't know if it's needed):

#include <thread>
#include <atomic>
#include <vector>
#include <iostream>
#include <cassert>

using namespace std;

//atomic_bool success = true;
bool success = true;

int main()
{
    vector<thread> v;
    for (int i = 0; i < 10; ++i)
    {
        v.emplace_back([=]
        {
            if (i == 5 || i == 6)
            {
                //success.store(false, memory_order_release);
                success = false;
            }
        });
    }
    for (auto& t : v)
        t.join();

    //assert(success.load(memory_order_acquire) == false);
    assert(success == false);

    cout << "Finished" << endl;
    cin.get();
    return 0;
}

Is there a possibility that main thread will read the success variable as true even though one of the workers set it to false?

I found that thread::join() is a full memory barrier (source) but does that imply synchronized-with relationship with the following read of success variable from the main thread, so that we're guaranteed to get newest value?

Is the fix I posted (in the commented code) necessary in this case (or maybe another fix if this one is wrong)?

Is there a possibility that read of success variable will be optimized away (since it's not volatile) and we will get old value regardless of suppossed to exist implicit memory barrier on thread::join?

The code is suppossed to work on multiple architectures (cannot remember all of them, I don't have makefile in front of me) but there are atleast x86, amd64, itanium, arm7.

Thanks for any help with this.

Edit: I've modified the example, because in real situation more then one thread can try to write to success variable.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The code above represents a data race, and the use of join cannot change that fact. If only one thread wrote to the variable, it would be fine. But you have two threads writing to it, with no synchronization between them. That's a data race.

join simply means "all side effects of that thread's operation have completed and are now visible to you." That does not create ordering or synchronization between that thread and any thread other than your own.

If you used an atomic_bool, then it wouldn't be UB; it would be guaranteed to be false. But because there is a data race, you get pure UB. It might be true, false, or nasal demons.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...