Accessing a field of the class from a different thread - c++

I have a class that contains a vector of Facebook friends data:
std::vector<FBFriend> m_friends
The FB is a very simple struct:
struct FBFriend
{
std::string ID;
std::string photoPath;
std::string name;
bool installed;
int score;
};
When I download the data from FB (in an async thread), I iterate over the m_friends field, to assign the corresponding picture, but I get bad access error.
Any idea?
Thanks.

When accessing a variable from multiple threads the reads and writes must be synchronized to avoid a data race.
Here's a simple example of how you can synchronize access using std::mutex and std::lock_guard:
std::mutex m;
std::vector<FBFriend> v;
// Add two FBFriend to vector.
v.push_back({"user1", "/photos/steve", "Steve", true, 0});
v.push_back({"user2", "/photos/laura", "Laura", true, 0});
// Change element in vector from a different thread.
auto f = std::async(std::launch::async, [&] {
std::lock_guard<std::mutex> lock(m); // Aquire lock before writing.
v[0].photoPath = "/images/steve";
});
f.wait(); // Wait for task to finish.
std::cout << v[0].photoPath << std::endl;
std::cout << v[1].photoPath << std::endl;
Output:
/images/steve
/photos/laura

Related

Sharing common data element between threads

I am trying to use c++ queue. I know queue element can be accessed by existing threads, but I want to use same queue element. It will be used by all threads, e.g: same video frame I want to use between thread1 and thread2.
Once it's processed by two threads I want to pop next video frame. I know threads will access individual elements (queue element 1 by thread1 and queue element2 by thread2), but I want to access queue element 1 by both threads. I am unable to lock single buffer for both threads.
Please help me to share same queue element between threads.
You could put each frame in an envelope containing a counter that you decrease every time the queue is pop:ed. When the counter reaches zero, you remove the element. Example:
struct envelope_t {
int count;
frame_t frame;
envelope_t(const frame_t& f) : count(2), frame(f) {}
};
class myqueue {
std::queue<envelope_t> data;
std::mutex mtx_data;
std::condition_variable cv_data;
public:
template<class... Args>
decltype(auto) emplace(Args&&... args) {
std::lock_guard<std::mutex> lock(mtx_data);
auto rv = data.emplace(std::forward<Args>(args)...);
cv_data.notify_one();
return rv;
}
frame_t pop() {
std::unique_lock<std::mutex> lock(mtx_data);
while(data.size() == 0) cv_data.wait(lock);
if(--data.front().count) {
cv_data.notify_one();
return data.front().frame;
} else {
auto msg = std::move(data.front().frame);
data.pop();
return msg;
}
}
};

protected data structure elements passed by value across functions

I have a network application where multiple users have their userContext saved in the server. Users continuously send different requests to the server and the server processes them asynchronously using a thread pool and an event loop (like epoll for example).
All the users have their own ID. This id is unique with respect to the server. The server stores the user context in a map<int,userContext>. When the server receives a message from one user, it decodes the message. It also finds what is the request and userID etc. Then the server processes the request and it also updates (as required, state machine updates in the userContext current state) the stored userContext in the map.
In my application, there is a lot of such procedure calls (few are nested also) and I am passing the user context by value. I can not pass the reference of the map values. (then protection no longer exists).
Below is a sample implementation of userContextStore and two procedure.
class userContext {
public:
int id;
int value1;
int value2;
userContext():id(-1),value1(-1),value2(-1){}
userContext(const userContext &context) {
this->id = context.id;
this->value1 = context.value1;
this->value2 = context.value2;
}
};
class contextStore {
public:
map<int,userContext> Map;
std::mutex m;
void update(userContext context,int id) {
lock_guard<std::mutex> lock(m);
if(Map.find(id) != Map.end()) {
Map[id] = context;
return;
}
Map[id] = context;
}
userContext getUserContext(int id) {
lock_guard<std::mutex> lock(m);
userContext context(Map[id]);
return context;
}
void printContext(int id) {
lock_guard<std::mutex> lock(m);
if(Map.find(id) != Map.end()) {
userContext temp(Map[id]);
cout << temp.value1 << endl;
cout << temp.value2 << endl;
}
}
};
void procedureA(contextStore &store,userContext context) {
// do some long processing using the provided context
// change context copy in between
// based on the above processing
context.value1 += 20; // example of a change
int id = context.id;
store.update(context,id);
}
void procedureB(contextStore &store,int id) {
userContext context(store.getUserContext(id));
// do some other long processing
// change context copy in between
context.value1 -= 10; // example of a change
store.update(context,id);
}
Is there any better (possibly way to avoid object copy multiple times) to pass the userContext objects for the required modification inside a particular procedure call?
The second issue is that I am using a fat lock protecting the entire map. In this case, if one user request is under process in the server, then other user request's will not be processed. (because of the lock protects the entire map). Is there any way to have to fine grain lock for such situation?
Thanks!

c++11 multi-reader / multi-writer queue using atomics for object state and perpetual incremented indexes

I am using atomics and a circular buffer in order to implement a multi-reader threads, multi-writer threads object pool.
It is difficult to investigate because instrumenting code leads to bug vanishment !
The model
Producers (or writer threads) request an Element to the Ring in order to 'prepare' the element. When terminated, the writer thread changes the element state so a reader can 'consume' it. After that, the element becomes available again for writing.
Consumers (or reader threads) request an object to the Ring in order to 'read' the object.
After 'releasing' the object, the object is in a state::Ready state, eg available to be consume by a reader thread.
It can fail if no object is available eg the next free object in the Ring is not on state::Unused state.
The 2 classes, Element and Ring
Element :
to be written, a writer thread must successfully exchange the _state member from state::Unused to state::LockForWrite
when finished, the writer thread force the state to state::Ready (it should be the only to handle this Element)
to be read, a rader thread must successfully exchange the _state member from state::Ready to state::LockForRead
when finished, the reader thread force the state to state::Unused (it should be the only to handle this Element)
Summarized :
writers lifecycle : state::Unused -> state::LockForWrite -> state::Ready
readers lifecycle : state::Ready -> state::LockForRead -> state::Unused
Ring
has a vector of Element , seen as a circular buffer.
std::atomic<int64_t> _read, _write; are the 2 indexes used to access the elements via :
_elems[ _write % _elems.size() ] for writers,
_elems[ _read % _elems.size() ] for readers.
When a reader has successfully LockForRead an object, the _read index is incremented.
When a writer has successfully LockForWrite an object, the _write index is incremented.
The main :
We add to a vector some writers and readers threads sharing the same Ring. Each thread just try to get_read or get_write element and release them just after.
Based on Element transition everything should be fine but one can observe that the Ring at some point gets blocked like because some elements in the ring are in state state::Ready with a _write % _elems.size() index pointing on it and symetrically, some elements in the ring are in state state::Unused with a _read % _elems.size() index pointing on it ! Both = deadlock.
#include<atomic>
#include<vector>
#include<thread>
#include<iostream>
#include<cstdint>
typedef enum : int
{
Unused, LockForWrite, Ready, LockForRead
}state;
class Element
{
std::atomic<state> _state;
public:
Element():_state(Unused){ }
// a reader need to successfully make the transition Ready => LockForRead
bool lock_for_read() { state s = Ready; return _state.compare_exchange_strong(s, LockForRead); }
void unlock_read() { state s = Unused; _state.store(s); }
// a reader need to successfully make the transition Unused => LockForWrite
bool lock_for_write() { state s = Unused; return _state.compare_exchange_strong(s, LockForWrite); }
void unlock_write() { state s = Ready; _state.store(s); }
};
class Ring
{
std::vector<Element> _elems;
std::atomic<int64_t> _read, _write;
public:
Ring(size_t capacity)
: _elems(capacity), _read(0), _write(0) {}
Element * get_for_read() {
Element * ret = &_elems[ _read.load() % _elems.size() ];
if (!ret->lock_for_read()) // if success, the object belongs to the caller thread as reader
return NULL;
_read.fetch_add(1); // success! incr _read index
return ret;
}
Element * get_for_write() {
Element * ret = &_elems[ _write.load() % _elems.size() ];
if (!ret->lock_for_write())// if success, the object belongs to the caller thread as writer
return NULL;
_write.fetch_add(1); // success! incr _write index
return ret;
}
void release_read(Element* e) { e->unlock_read();}
void release_write(Element* e) { e->unlock_write();}
};
int main()
{
const int capacity = 10; // easy to process modulo[![enter image description here][1]][1]
std::atomic<bool> stop=false;
Ring ring(capacity);
std::function<void()> writer_job = [&]()
{
std::cout << "writer starting" << std::endl;
Element * e;
while (!stop)
{
if (!(e = ring.get_for_write()))
continue;
// do some real writer job ...
ring.release_write(e);
}
};
std::function<void()> reader_job = [&]()
{
std::cout << "reader starting" << std::endl;
Element * e;
while (!stop)
{
if (!(e = ring.get_for_read()))
continue;
// do some real reader job ...
ring.release_read(e);
}
};
int nb_writers = 1;
int nb_readers = 2;
std::vector<std::thread> threads;
threads.reserve(nb_writers + nb_readers);
std::cout << "adding writers" << std::endl;
while (nb_writers--)
threads.push_back(std::thread(writer_job));
std::cout << "adding readers" << std::endl;
while (nb_readers--)
threads.push_back(std::thread(reader_job));
// wait user key press, halt in debugger after 1 or 2 seconds
// in order to reproduce problem and watch ring
std::cin.get();
stop = true;
std::cout << "waiting all threads...\n";
for (auto & th : threads)
th.join();
std::cout << "end" << std::endl;
}
This "watch debugger screeshot" has been took pausing the program after running 1 second. As you can see, _read is pointing to the element 8 marked as state::Unused so no transition can unblock this state for this reader, except a writer but _write index is pointing on element 0 with state state::Ready !
My question: what did I missed in this ? Structurally I am sure the sequence is correct but I am missing some atomic trick ...
os tested : rhel5/gcc 4.1.2, rhel 7/gcc 4.8, win10/ms visual 2015, win10/mingw
Yann's answer is correct about the problem: your threads can create "holes" in the sequence by reading and writing elements out-of-order if there's a delay between the read/write lock and the increment of the index. The fix is to verify that the index has not changed between the initial read and the increment, a la:
class Element
{
std::atomic<state> _state;
public:
Element():_state(Unused){ }
// a reader need to successfully make the transition Ready => LockForRead
bool lock_for_read() {
state s = Ready;
return _state.compare_exchange_strong(s, LockForRead);
}
void abort_read() { _state = Ready; }
void unlock_read() { state s = Unused; _state.store(s); }
// a reader need to successfully make the transition Unused => LockForWrite
bool lock_for_write() {
state s = Unused;
return _state.compare_exchange_strong(s, LockForWrite);
}
void abort_write() { _state = Unused; }
void unlock_write() { state s = Ready; _state.store(s); }
};
class Ring
{
std::vector<Element> _elems;
std::atomic<int64_t> _read, _write;
public:
Ring(size_t capacity)
: _elems(capacity), _read(0), _write(0) {}
Element * get_for_read() {
auto i = _read.load();
Element * ret = &_elems[ i % _elems.size() ];
if (ret->lock_for_read()) {
// if success, the object belongs to the caller thread as reader
if (_read.compare_exchange_strong(i, i + 1))
return ret;
// Woops, reading out of order.
ret->abort_read();
}
return NULL;
}
Element * get_for_write() {
auto i = _write.load();
Element * ret = &_elems[ i % _elems.size() ];
if (ret->lock_for_write()) {
// if success, the object belongs to the caller thread as writer
if (_write.compare_exchange_strong(i, i + 1))
return ret;
// Woops, writing out of order.
ret->abort_write();
}
return NULL;
}
void release_read(Element* e) { e->unlock_read();}
void release_write(Element* e) { e->unlock_write();}
};
You do not have atomic section around the increment of the two shared counters _read and _write.
That looks bad to me, you could switch another element without meaning to.
Imagine this scenario,
1 reader R1 and 1 writer W are happily cooperating.
Reader 2 executes : Element * ret = &_elems[ _read.load() % _elems.size() ];
and gets pushed off the cpu.
Now R1 and W are still playing together, so the positions of _read and _write are now arbitrary w.r.t. the element ret that R2 is pointing.
Now at some point R2 gets scheduled, and it so happens that *ret_ is readable (again possibly, R1 and W went around the block a few times).
Ouch, as you see, we will read it, and increment "_read", but _read has no relation to _ret. This creates kind of holes, elements that have not been read, but that are below _read index.
So, make critical sections to ensure that increment of _read/_write is done in the same semantic step as the actual lock.

RxCpp: how to control subject observer's lifetime when used with buffer_with_time

The purpose of the following code is to have various classes publish data to an observable. Some classes will observe every data, some will observe periodically with buffer_with_time().
This works well until the program exits, then it crashes, probably because the observer using buffer_with_time() is still hanging on to some thread.
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { _subscriber.on_completed(); }
void publish(std::string data) { _subscriber.on_next(data); }
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo()
{
Data data;
auto period = std::chrono::milliseconds(30);
auto s1 = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.subscribe([](std::vector<std::string>& data)
{ std::cout << data.size() << std::endl; });
data.publish("test 1");
data.publish("test 2");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
I tried calling "s1.unsubscribe()", and various as_blocking(), from(), merge(), but still can't get the program to exit gracefully.
Note that I used "subjects" here because "publish" can then be called from different places (which can be from different threads). I am not sure if this is the best mechanism to do that, I am open to other ways to accomplish that.
Advice?
This is very close to working..
However, having the Data destructor complete the input while also wanting the subscription to block the exit of foo until input is completed makes this more complex.
Here is a way to ensure that foo blocks after Data destructs. This is using the existing Data contract.
void foo1()
{
rxcpp::observable<std::vector<std::string>> buffered;
{
Data data;
auto period = std::chrono::milliseconds(30);
buffered = data.observable()
.buffer_with_time(period , rxcpp::observe_on_new_thread())
.publish().ref_count();
buffered
.subscribe([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
data.publish("test 1");
data.publish("test 2");
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
}
buffered.as_blocking().subscribe();
printf("exit foo1\n");
}
Alternatively, the changing the shape of Data (add a complete method) would allow the following code:
struct Data
{
Data() : _subscriber(_subject.get_subscriber()) { }
~Data() { complete(); }
void publish(std::string data) { _subscriber.on_next(data); }
void complete() {_subscriber.on_completed();}
rxcpp::observable<std::string> observable() { return _subject.get_observable(); }
private:
rxcpp::subjects::subject<std::string> _subject;
rxcpp::subscriber<std::string> _subscriber;
};
void foo2()
{
printf("foo2\n");
Data data;
auto newthread = rxcpp::observe_on_new_thread();
auto period = std::chrono::milliseconds(30);
auto buffered = data.observable()
.buffer_with_time(period , newthread)
.tap([](const std::vector<std::string>& data)
{ printf("%lu\n", data.size()); },
[](){printf("data complete\n");});
auto emitter = rxcpp::sources::timer(std::chrono::milliseconds(0), newthread)
.tap([&](long) {
data.publish("test 1");
data.publish("test 2");
data.complete();
});
// hope to call something here so s1's thread can be joined.
// program crashes upon exit
buffered.combine_latest(newthread, emitter).as_blocking().subscribe();
printf("exit foo2\n");
}
I think that this better expresses the dependencies..

How can I synchronize three threads?

My app consist of the main-process and two threads, all running concurrently and making use of three fifo-queues:
The fifo-q's are Qmain, Q1 and Q2. Internally the queues each use a counter that is incremented when an item is put into the queue, and decremented when an item is 'get'ed from the queue.
The processing involve two threads,
QMaster, which get from Q1 and Q2, and put into Qmain,
Monitor, which put into Q2,
and the main process, which get from Qmain and put into Q1.
The QMaster-thread loop consecutively checks the counts of Q1 and Q2 and if any items are in the q's, it get's them and puts them into Qmain.
The Monitor-thread loop obtains data from external sources, package it and put it into Q2.
The main-process of the app also runs a loop checking the count of Qmain, and if any items, get's an item
from Qmain at each iteration of the loop and process it further. During this processing it occasionally
puts an item into Q1 to be processed later (when it is get'ed from Qmain in turn).
The problem:
I've implemented all as described above, and it works for a randomly (short) time and then hangs.
I've managed to identify the source of the crashing to happen in the increment/decrement of the
count of a fifo-q (it may happen in any of them).
What I've tried:
Using three mutex's: QMAIN_LOCK, Q1_LOCK and Q2_LOCK, which I lock whenever any get/put operation
is done on a relevant fifo-q. Result: the app doesn't get going, just hangs.
The main-process must continue running all the time, must not be blocked on a 'read' (named-pipes fail, socketpair fail).
Any advice?
I think I'm not implementing the mutex's properly, how should it be done?
(Any comments on improving the above design also welcome)
[edit] below are the processes and the fifo-q-template:
Where & how in this should I place the mutex's to avoid the problems described above?
main-process:
...
start thread QMaster
start thread Monitor
...
while (!quit)
{
...
if (Qmain.count() > 0)
{
X = Qmain.get();
process(X)
delete X;
}
...
//at some random time:
Q2.put(Y);
...
}
Monitor:
{
while (1)
{
//obtain & package data
Q2.put(data)
}
}
QMaster:
{
while(1)
{
if (Q1.count() > 0)
Qmain.put(Q1.get());
if (Q2.count() > 0)
Qmain.put(Q2.get());
}
}
fifo_q:
template < class X* > class fifo_q
{
struct item
{
X* data;
item *next;
item() { data=NULL; next=NULL; }
}
item *head, *tail;
int count;
public:
fifo_q() { head=tail=NULL; count=0; }
~fifo_q() { clear(); /*deletes all items*/ }
void put(X x) { item i=new item(); (... adds to tail...); count++; }
X* get() { X *d = h.data; (...deletes head ...); count--; return d; }
clear() {...}
};
An example of how I would adapt the design and lock the queue access the posix way.
Remark that I would wrap the mutex to use RAII or use boost-threading and that I would use stl::deque or stl::queue as queue, but staying as close as possible to your code:
main-process:
...
start thread Monitor
...
while (!quit)
{
...
if (Qmain.count() > 0)
{
X = Qmain.get();
process(X)
delete X;
}
...
//at some random time:
QMain.put(Y);
...
}
Monitor:
{
while (1)
{
//obtain & package data
QMain.put(data)
}
}
fifo_q:
template < class X* > class fifo_q
{
struct item
{
X* data;
item *next;
item() { data=NULL; next=NULL; }
}
item *head, *tail;
int count;
pthread_mutex_t m;
public:
fifo_q() { head=tail=NULL; count=0; }
~fifo_q() { clear(); /*deletes all items*/ }
void put(X x)
{
pthread_mutex_lock(&m);
item i=new item();
(... adds to tail...);
count++;
pthread_mutex_unlock(&m);
}
X* get()
{
pthread_mutex_lock(&m);
X *d = h.data;
(...deletes head ...);
count--;
pthread_mutex_unlock(&m);
return d;
}
clear() {...}
};
Remark too that the mutex still needs to be initialized as in the example here and that count() should also use the mutex
Use the debugger. When your solution with mutexes hangs look at what the threads are doing and you will get a good idea about the cause of the problem.
What is your platform? In Unix/Linux you can use POSIX message queues (you can also use System V message queues, sockets, FIFOs, ...) so you don't need mutexes.
Learn about condition variables. By your description it looks like your Qmaster-thread is busy looping, burning your CPU.
One of your responses suggest you are doing something like:
Q2_mutex.lock()
Qmain_mutex.lock()
Qmain.put(Q2.get())
Qmain_mutex.unlock()
Q2_mutex.unlock()
but you probably want to do it like:
Q2_mutex.lock()
X = Q2.get()
Q2_mutex.unlock()
Qmain_mutex.lock()
Qmain.put(X)
Qmain_mutex.unlock()
and as Gregory suggested above, encapsulate the logic into the get/put.
EDIT: Now that you posted your code I wonder, is this a learning exercise?
Because I see that you are coding your own FIFO queue class instead of using the C++ standard std::queue. I suppose you have tested your class really well and the problem is not there.
Also, I don't understand why you need three different queues. It seems that the Qmain queue would be enough, and then you will not need the Qmaster thread that is indeed busy waiting.
About the encapsulation, you can create a synch_fifo_q class that encapsulates the fifo_q class. Add a private mutex variable and then the public methods (put, get, clear, count,...) should be like put(X) { lock m_mutex; m_fifo_q.put(X); unlock m_mutex; }
question: what would happen if you have more than one reader from the queue? Is it guaranteed that after a "count() > 0" you can do a "get()" and get an element?
I wrote a simple application below:
#include <queue>
#include <windows.h>
#include <process.h>
using namespace std;
queue<int> QMain, Q1, Q2;
CRITICAL_SECTION csMain, cs1, cs2;
unsigned __stdcall TMaster(void*)
{
while(1)
{
if( Q1.size() > 0)
{
::EnterCriticalSection(&cs1);
::EnterCriticalSection(&csMain);
int i1 = Q1.front();
Q1.pop();
//use i1;
i1 = 2 * i1;
//end use;
QMain.push(i1);
::LeaveCriticalSection(&csMain);
::LeaveCriticalSection(&cs1);
}
if( Q2.size() > 0)
{
::EnterCriticalSection(&cs2);
::EnterCriticalSection(&csMain);
int i1 = Q2.front();
Q2.pop();
//use i1;
i1 = 3 * i1;
//end use;
QMain.push(i1);
::LeaveCriticalSection(&csMain);
::LeaveCriticalSection(&cs2);
}
}
return 0;
}
unsigned __stdcall TMoniter(void*)
{
while(1)
{
int irand = ::rand();
if ( irand % 6 >= 3)
{
::EnterCriticalSection(&cs2);
Q2.push(irand % 6);
::LeaveCriticalSection(&cs2);
}
}
return 0;
}
unsigned __stdcall TMain(void)
{
while(1)
{
if (QMain.size() > 0)
{
::EnterCriticalSection(&cs1);
::EnterCriticalSection(&csMain);
int i = QMain.front();
QMain.pop();
i = 4 * i;
Q1.push(i);
::LeaveCriticalSection(&csMain);
::LeaveCriticalSection(&cs1);
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
::InitializeCriticalSection(&cs1);
::InitializeCriticalSection(&cs2);
::InitializeCriticalSection(&csMain);
unsigned threadID;
::_beginthreadex(NULL, 0, &TMaster, NULL, 0, &threadID);
::_beginthreadex(NULL, 0, &TMoniter, NULL, 0, &threadID);
TMain();
return 0;
}
You should not lock second mutex when you already locked one.
Since the question is tagged with C++, I suggest to implement locking inside get/add logic of the queue class (e.g. using boost locks) or write a wrapper if your queue is not a class.
This allows you to simplify the locking logic.
Regarding the sources you have added: queue size check and following put/get should be done in one transaction otherwise another thread can edit the queue in between
Are you acquiring multiple locks simultaneously? This is generally something you want to avoid. If you must, ensure you are always acquiring the locks in the same order in each thread (this is more restrictive to your concurrency and why you generally want to avoid it).
Other concurrency advice: Are you acquiring the lock prior to reading the queue sizes? If you're using a mutex to protect the queues, then your queue implementation isn't concurrent and you probably need to acquire the lock before reading the queue size.
1 problem may occur due to this rule "The main-process must continue running all the time, must not be blocked on a 'read'". How did you implement it? what is the difference between 'get' and 'read'?
Problem seems to be in your implementation, not in the logic. And as you stated, you should not be in any dead lock because you are not acquiring another lock whether in a lock.