Reputation:
Ok, I've a application which has two additional threads.
Thread one accesses object O and inserts data into a deque which is part of object O and increments a counter variable.
Thread two accesses object O and pulls out and deletes data from the deque and decrements the counter variable.
This turned out to give unexpected results since one thread tells me there are x elements inside of the deque and the other thread tells me there are no elements. I assume I have to use some kind of synchronization. I tried to use semaphore which I must have misunderstood since it didn't work (http://msdn.microsoft.com/en-us/library/windows/desktop/ms686946(v=vs.85).aspx).
So I want to know how to access a global object from two threads. Be aware that the access to the global object O happens quite often since the access is within a while loop which results in continues insertions and polls. (Would the possible solution block the other thread from accessing the object and therefore the while loop?)
So far I only know of semaphore and mutex but have never used any of them, please be so kind and enlighten me.
Upvotes: 0
Views: 580
Reputation: 154035
When accessing an object from multiple threads with one access possibly changing the object, you need some from of synchronization. For the scenario described you probably want to have a queue class which does the necessary thread protection and signalling. Here is a simple implementation:
#include <mutex>
#include <condition_variable>
#include <deque>
template <typename T>
class queue
{
private:
std::mutex d_mutex;
std::condition_variable d_condition;
std::deque<T> d_queue;
public:
void push(T const& value) {
{
std::unique_lock<std::mutex> lock(this->d_mutex);
d_queue.push_front(value);
}
this->d_condition.notify_one();
}
T pop() {
std::unique_lock<std::mutex> lock(this->d_mutex);
this->d_condition.wait(lock, [=]{ return !this->d_queue.empty(); });
T rc(std::move(this->d_queue.back()));
this->d_queue.pop_back();
return rc;
}
};
The code uses C++ 2011 constructs but it can easily be changed to avoid their use and rather use C++ 2003 constructs instead except that these aren't standardized.
The key points are:
std::mutex
is used to make sure only on thread accesses the queue at a time.true
and wait()
returns immediately, otherwise the thread is put to sleep until it gets a signal at which point the condition is reevaluated. Note, that the condition may be evaluated multiple times because there may be spurious wake-up to the condition variable.this
; member variables cannot be captured directly because they are not part of the local context.pop()
is returned by value: the moment the lock gets release, the container may be changed, making it impossible to return objects by reference, even if they were put into a suitable location.The main reason this is somewhat of a toy example is that it doesn't have a nice way to shut down the system: If a thread is blocked on the queue it waits until there is another object. A real implementation would have some way to signal that it is time to shut down, possibly throwing an exception from pop()
. Also, sometimes it is useful to have queue which doesn't force blocking to extract an object. Instead, it would have a function try_pop()
which acquires a lock, checks if the queue is non-empty and depending on the result extracts and object or signals failure. A function like this is easy to implement, though.
Upvotes: 0
Reputation: 28362
The easiest way would be to use EnterCriticalSection
/LeaveCriticalSection
around the code you want to use in an exclusive manner:
CRITICAL_SECTION critSect;
// Later in the code
EnterCriticalSection(&critSect);
// Do stuff with O
LeaveCriticalSection(&critSect);
You would of course use this in both threads. Only one thread can be inside the enter/leave zone at a time. The EnterCriticalSection
will block until the other thread calls LeaveCriticalSection
.
Upvotes: 1