0

I have a shared object of type:

struct A {
  int x;
  int y;
  int z;
};

A obj;

There is 2 threads running in parallel.

Thread #1 modifies object's members:

// .. some code before
obj.x = 42;
obj.y = 42;
obj.z = 42;
// .. now thread #2 can read obj

Thread #2 reads object's members:

// .. some code before
int x = obj.x;
int y = obj.y;
int z = obj.z;
// .. some code after

How to synchronize the flow most efficiently that the thread #2 reads object's members only after thread #1 modified them all?

mikeg
  • 63
  • 3
  • 10

2 Answers2

0

Use std::atomic here.

boost::atomic<int> x { INT_MAX };

// thread1:
while (x.load(memory_order_acquire) == INT_MAX);

// thread2:
x.store(42,memory_order_release);

EDIT add runnable example

main.cpp

#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>

struct Foo {
    Foo(): x_(0) {}
    std::atomic<int> x_;
};

using namespace std;

int main() {
    Foo foo;
    thread th1(
        [&]() {
            cout << "thread1 Waiting for thread2 setting value for x" << endl;
            while (foo.x_.load(memory_order_acquire) == 0);
            int current = foo.x_.load(memory_order_acquire);
            cout << "thread 1 print current value of x is " << current << endl;
        });
    thread th2(
        [&]() {
            std::chrono::milliseconds dura( 2000 );
            std::this_thread::sleep_for( dura );
            cout << "thread2 set up value for x" << endl;
            foo.x_.store(42,memory_order_release);
        });
    th1.join();
    th2.join();
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.4)
project(atomicExample)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++11")

set(SOURCE_FILES main.cpp)
add_executable(atomicExample ${SOURCE_FILES})
qqibrow
  • 2,942
  • 1
  • 24
  • 40
  • wouldn't it provide member wise synchronization in that case? I was hoping to see object wise synchronization. – mikeg Jan 16 '15 at 08:45
  • also thread #2 will be reading obj more than once but in your example it will only succeed reading obj first time, when the members initialized with INT_MAX. – mikeg Jan 16 '15 at 08:56
  • Above is simple code to show usage of atomic. I added a complete runnable example. Please check – qqibrow Jan 16 '15 at 15:25
0

You can use std::mutex to synchronize critical sections of your code. std::lock_guard locks a mutex and releases it when the lock_guard goes out of scope. I've also added a condition variable to ensure that thread2() waits for thread1() to finish assigning values to obj before continuing.

Example:

#include <mutex>
#include <condition_variable>

struct A {
    int x;
    int y;
    int z;
};

A obj;

std::mutex m;
std::condition_variable cv;
bool thread1Done = false;

void thread1()
{
    std::lock_guard<std::mutex> lock( m );
    obj.x = 42;
    obj.y = 42;
    obj.z = 42;
    thread1Done = true;
    cv.notifyAll();
}

void thread2()
{
    std::unique_lock<std::mutex> lock( m );
    while ( !thread1Done ) {
        cv.wait( lock );
    }

    int x = obj.x;
    int y = obj.y;
    int z = obj.z;
}
Julian
  • 1,688
  • 1
  • 12
  • 19
  • using lock is for sure a solution. But in the question it specify "most efficiently" here. And also, it requires " thread #2 reads object's members only after thread #1 modified them all", so you'd better change your solution to use a conditional variable. – qqibrow Jan 16 '15 at 16:07
  • @qqibrow Good call, that was an oversight on my behalf. I've edited my solution. Better? – Julian Jan 16 '15 at 16:19
  • hmm... just one small error. the lock in thread2 should be unique_lock. check this. http://stackoverflow.com/questions/20516773/stdunique-lockstdmutex-or-stdlock-guardstdmutex – qqibrow Jan 16 '15 at 16:37