Sign in to follow this  
WalterTamboer

Threading Design

Recommended Posts

WalterTamboer    181
Hello, I'm someone that's always looking for the perfect design for an application. I can't stand it when someone is creating ugly code so I'm always using coding guidelines for my projects. One of the rules is: Don't use global variables unless there isn't any other way. With this in mind; hear my problem ;) I want to create a multithreaded game in C++. Some code:
#include "stdafx.h"
#include "Thread1.h"
#include "Thread2.h"

int main(int argc, char *argv[])
{
	Thread1 *Thrd1 = new Thread1(); // This could be our render thread...
	Thread2 *Thrd2 = new Thread2(); // And this could be our drink some beer thread...

	Thrd1->Start();
	Thrd2->Start();

	delete Thrd1;
	delete Thrd2;

	return 0;
}

Just a little application which is starting two threads and will execute them. Now these threads both have a run method where they're printing text to the screen (for example). This of course, needs be synchronized.
// Thread1
while (IsRunning)
{
	Lock->Acquire();
	std::cout << "Written from thread 1" << std::endl;
	Lock->Release();
}

// Thread2
while (IsRunning)
{
	Lock->Acquire();
	std::cout << "Written from thread 2" << std::endl;
	Lock->Release();
}


As you see is the lock used in both threads... hey this is in conflict with my coding guidelines ;) So my question: How can I use multithreading in an elegant way without the use of global variables.

Share this post


Link to post
Share on other sites
Telastyn    3777
Same way you would in any other application, pass along Lock as a parameter (or member of a parameter) to both Thread objects.

Share this post


Link to post
Share on other sites
TheUnbeliever    963
I don't think there is such a thing as an elegant implementation of multithreading for anything nontrivial - or if there is, I haven't seen it (possibly Eiffel?). Then it becomes orders of magnitude harder (or so it seems, anyway) when you're not just dealing with multiple threads with multiple cores (because two cores might try to access the same data at the same time).

However, if you're acquiring a lock (I presume you're doing so atomically, of course - otherwise you simply circumvent any protection which the lock offers you) then you're not acquiring a global lock - you're acquiring a lock on a single object - so associate a lock with that object (as a member?) rather than having a single global variable.

Or perhaps there's something more complex that I'm missing...

Share this post


Link to post
Share on other sites
Kylotan    10013
Quote:
Original post by Telastyn
Same way you would in any other application, pass along Lock as a parameter (or member of a parameter) to both Thread objects.


Or encapsulate the lock as part of the resource that multiple threads can access. Why are you (the original poster) sharing the std::cout global across threads anyway? ;)

Share this post


Link to post
Share on other sites
WalterTamboer    181
Thnx for the answers. Hmm just passing the lock as a parameter is actually not a bad idea :)

Quote:
However, if you're acquiring a lock (I presume you're doing so atomically, of course - otherwise you simply circumvent any protection which the lock offers you) then you're not acquiring a global lock - you're acquiring a lock on a single object - so associate a lock with that object (as a member?) rather than having a single global variable.

Or perhaps there's something more complex that I'm missing...


Uhm that Lock can be anything but let's just assume it's a class which holds a handle of a mutex.

Quote:
Why are you sharing the std::cout global across threads anyway? ;)
It's just an example ;)

Arn't there any good articles on how to write good looking code?

Share this post


Link to post
Share on other sites
TheUnbeliever    963
Quote:
Original post by WalterTamboer
Quote:
However, if you're acquiring a lock (I presume you're doing so atomically, of course - otherwise you simply circumvent any protection which the lock offers you) then you're not acquiring a global lock - you're acquiring a lock on a single object - so associate a lock with that object (as a member?) rather than having a single global variable.

Or perhaps there's something more complex that I'm missing...


Uhm that Lock can be anything but let's just assume it's a class which holds a handle of a mutex.


I don't follow as to how this voids my suggestion (or indeed Kylotan's, since that is what I mean). Just define all 'Lock' types (mutexes, semaphores - whatever) to have a basic interface (or perhaps even define a larger class of synchronisation procedures) from which they inherit so that you can take advantage of scope for polymorphism and then still have them as a member - which you can then call the Lock->Acquire method on. This way, the lock for the object is associated with the object, and is not a separate entity (which, really, it's not) - also has the benefit of being in scope whenever the object being used is in scope.

Share this post


Link to post
Share on other sites
Bregma    9214
Quote:
Original post by WalterTamboer
Quote:
Why are you sharing the std::cout global across threads anyway? ;)
It's just an example ;)

It's not just an example. It's the answer to your question. Think about it.

--smw

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this