views:

239

answers:

5

I'm something of an intermediate programmer, but relatively a novice to multi-threading. At the moment, I'm working on an application with a structure similar to the following:

class Client  
{  
    public:  
      Client();

    private:
   // These are all initialised/populated in the constrcutor.
      std::vector<struct clientInfo> otherClientsInfo;
      ClientUI* clientUI;
      ClientConnector* clientConnector;
}

class ClientUI
{
    public:
      ClientUI(std::vector<struct clientInfo>* clientsInfo);

    private:
      // Callback which gets new client information
      // from a server and pushes it into the otherClientsInfo vector.
      synchClientInfo();
      std::vector<struct clientInfo>* otherClientsInfo;
}

class ClientConnector
{
    public:
      ClientConnector(std::vector<struct clientInfo>* clientsInfo);

    private:
      connectToClients();
      std::vector<struct clientInfo>* otherClientsInfo;
}

Somewhat a contrived example, I know. The program flow is this:

  • Client is constructed and populates otherClientsInfo and constructs clientUI and clientConnector with a pointer to otherClientsInfo.

  • clientUI calls synchClientInfo() anytime the server contacts it with new client information, parsing the new data and pushing it back into otherClientsInfo or removing an element.

  • clientConnector will access each element in otherClientsInfo when connectToClients() is called but won't alter them.

My first question is whether my assumption that if both ClientUI and ClientConnector access otherClientsInfo at the same time, will the program bomb out because of thread-unsafety?

If this is the case, then how would I go about making access to otherClientsInfo thread safe, as in perhaps somehow locking it while one object accesses it?

A: 

See http://stackoverflow.com/questions/244316/reader-writer-locks-in-c

and

http://msdn.microsoft.com/en-us/library/ms682530%28VS.85%29.aspx

The first one is probably a bit advanced for you. You can start with the Critical section (link 2).

I am assuming you are using Windows.

Tanmay
I'm actually developing for Linux and BSD.Thank you for the references, I'll check them out now.
Conor
A: 

if both ClientUI and ClientConnector access otherClientsInfo at the same time, will the program bomb out because of thread-unsafety?
Yes, STL containers are not thread-safe.

If this is the case, then how would I go about making access to otherClientsInfo thread safe, as in perhaps somehow locking it while one object accesses it?
In the most simple case a mutual exclusion pattern around the access to the shared data... if you'd have multiple readers however, you would go for a more efficient pattern.

Georg Fritzsche
It is my understanding that mutexes prevent threads from accessingdata in the same function, is this correct?Maybe I've misunderstood your answer, but what is happening in the programme is that the vector otherClientsInfo maybe accessed at the same time by two different objects of different types, will mutexes prevent one object accessing it while the other object accesses it?Also, can you point me in the direction of a good reference on readers and the associated patterns?Thank you for your reply.
Conor
Mutexes are a tool that help you avoid simultaneous access to critical data, see for example http://en.wikipedia.org/wiki/Mutual_exclusion
Georg Fritzsche
And yes, the problem is simultaneous access... and that is where locks like mutexes help you.
Georg Fritzsche
And... for basic introductions you can start with reading on wikipedia - that will give you an overview. In the long run though, you should read a good book that gives you a deeper understanding of the whole multithreading world. For C++ this one is recommendable: http://www.manning.com/williams/
Georg Fritzsche
Ah ok, I'm following now, pardon my misunderstanding. I'll probably check out that book as it's an area I'd like to become skilled in. Thank you for you help and for the recommendation!
Conor
A: 

Is clientConnector called from the same thread as synchClientInfo() (even if it is all callback)? If so, you don't need to worry about thread safety at all.

If you want to avoid simultanous access to the same data, you can use mutexes to protect the critical section. For exmample, mutexes from Boost::Thread

drhirsch
+1  A: 

My first question is whether my assumption that if both ClientUI and ClientConnector access otherClientsInfo at the same time, will the program bomb out because of thread-unsafety?

Yes. Most implementations of std::vector do not allow concurrent read and modification. ( You'd know if you were using one which did )

If this is the case, then how would I go about making access to otherClientsInfo thread safe, as in perhaps somehow locking it while one object accesses it?

You would require at least a lock ( either a simple mutex or critical section or a read/write lock ) to be held whenever the vector is accessed. Since you've only one reader and writer there's no point having a read/write lock.

However, actually doing that correctly will get increasingly difficult as you are exposing te vector to the other classes, so will have to expose the locking primitive too, and remember to acquire it whenever you use the vector. It may be better to expose addClientInfo, removeClientInfo and const and non-const foreachClientInfo functions which encapsulate the locking in the Client class rather than having disjoint bits of the data owned by the client floating around the place.

Pete Kirkham
I am using the QT toolkit, which has a QVector class whose functions are reentrant. I am not sure if reentrancy will solve my problem in this case, but will deriving from the QVector or wrapping a std::vector in a class and providing the functions you suggested with mutexes provide me with a solution?
Conor
Putting mutexs around all accesses to the vector will provide a solution. It's easier to do that if you don't expose the vector so all accesses occur with the one class, hence the functions to manipulate it. I don't know QT so can't really comment on whether it would be safe.
Pete Kirkham
And then just pass a pointer to the wrapper class to the constructor of both ClientConnector and ClientUI? I might take this idea and use it with QVector, it'd probably make more sense to use QT's types when coding with QT... Thank you very much for your help.
Conor
A: 

In order to ensure that access to the otherClientsInfo member from multiple threads is safe, you need to protect it with a mutex. I wrote an article about how to directly associate an object with a mutex in C++ over on the Dr Dobb's website:

http://www.drdobbs.com/cpp/225200269

Anthony Williams