Sign in to follow this  
EnlightenedOne

Boost shared_mutex is there a total mutex's sharing method I can call?

Recommended Posts

I have a problem with using multiple threads and using a barrier, due to debugging and the complexity of states between my many threads I cannot use interrupts and an actual barrier variable.

You can skip to the end line for a rundown of what I need or read the fine print here.

I need an atmoc way to see the number of threads that are waiting inside a shared mutex.

These are the variables I use.

boost::condition_variable_any multiThreadLinkReady;
boost::shared_mutex smutDependancyThreadCustomBarrierReady;
bool boolIsSceneReady;

This is the code I run to wait until they are all ready, I cannot lock with the wait value set, so I need to atomically check this in the other function to garuntee every thread gets awoken when every thread is gathered.

 

void waitUntilAllReady()
{
mutAccessData.lock();

if (boolIsSceneReady == false)
{
intThreadsCaughtCountPost++;

mutAccessData.unlock();

//The thread is set to frozen to be awoken on the next line when the class is ready.
multiThreadLinkReady.wait(smutDependancyThreadCustomBarrierReady);

//So we can reuse this on the next level loaded we need to decrement the counter.
mutAccessData.lock();

intThreadsCaughtCountPost--;

mutAccessData.unlock();
}
else
{
//Not impossible to reach here but very unlikely depends on lots of thread lag.
mutAccessData.unlock();
}
}



Then there is this threaded function which only one thread uses to manage the other threads, I need another if to check that the smutDependancyThreadCustomBarrierReady has the TOTALTHREADSLOADINGSCENE attached to it before allowing notify to be called or my threads never wake up!



void wakeUpIfAllReady()
{
mutAccessData.lock();

if (intThreadsCaughtCountPost >= TOTALTHREADSLOADINGSCENE)
{
multiThreadLinkReady.notify_all();
boolIsSceneReady = true;
}

mutAccessData.unlock();
}



Does anyone know of a method in boost to perform the function in the title?

Share this post


Link to post
Share on other sites
I don't use boost threading so I might be a bit off, but -- When you call wait, it calls unlock on smutDependancyThreadCustomBarrierReady, right? It sounds like you should lock smutDependancyThreadCustomBarrierReady first with a shared_lock and then pass this lock to the wait function?

Also, when you call wait it's actually allowed to resume before notify is called, so, before proceeding with "intThreadsCaughtCountPost--", you should check that boolIsSceneReady is true, and if not, wait again.

Share this post


Link to post
Share on other sites
Hodgman - When you call wait my understanding is that it is added to the condition variables, so when I perform.

multiThreadLinkReady.wait(smutDependancyThreadCustomBarrierReady);

"Also, when you call wait it's actually allowed to resume before notify is called" - The thread is added to those with a shared lock on mutex multiThreadLinkReady. How can a thread resume before it is notified to be awoken?!? if its possible (and I have never seen it) that would change the game alot.

The issue is that the notify function can notify when the boolean is changed before the other thread actually goes into the wait mechanism and is added to the list of threads waiting on the semaphore. I cant obviously change the values in the midst of going into wait with a timed lock because on wait any timed processes the thread had going are also set to wait.

Scourage - I will head to the other thread now.

Share this post


Link to post
Share on other sites
I tried to modify the boost library but to no avail.

My code.

void wakeUpIfAllReady()
{
mutAccessData.lock();

if (intThreadsCaughtCountPost >= TOTALTHREADSLOADINGSCENE)
{
if (multiThreadLinkReady.get_total_count() == TOTALTHREADSLOADINGSCENE)
{
multiThreadLinkReady.notify_all();
boolIsSceneReady = true;
}
}

mutAccessData.unlock();
}



Boost file "condition_variable.hpp"


long get_total_count()
{
long lngTemp = 0;

if(detail::interlocked_read_acquire(&total_count))
{
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
if (!total_count)
{
return -1;
}
else
{
lngTemp = total_count;
}
}

return lngTemp;
}



I was feeling good about my patch until I had this issue.

modified boost error

Is there a prototype I need to change to hack together this correction?

Share this post


Link to post
Share on other sites
I am going to need to rewrite that class to get rid of the unnecessary integers counting up and down the total gathered threads when I am using part of conditional variable to do that test anyway!

Thanks for your suggestions everyone!

[Edited by - EnlightenedOne on October 10, 2010 5:54:37 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by EnlightenedOne
"Also, when you call wait it's actually allowed to resume before notify is called" - The thread is added to those with a shared lock on mutex multiThreadLinkReady. How can a thread resume before it is notified to be awoken?!? if its possible (and I have never seen it) that would change the game alot.
From the boost docs on condition_variable_any
Quote:
template<typename lock_type> void wait(lock_type& lock)

Effects:
Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously. When the thread is unblocked (for whatever reason), the lock is reacquired by invoking lock.lock() before the call to wait returns. The lock is also reacquired by invoking lock.lock() if the function exits with an exception.
Postcondition:
lock is locked by the current thread.
The "or spuriously" part means it can do it whenever it wants to.

Share this post


Link to post
Share on other sites
How can any state critical system (I have never heard of one otherwise) be dependent on something that works "spuriously"?

I guess I need to search for a new concept or assume spuriously is just a technical nit pick incase its impossible to make the lock in the first place due to some lower level fault. If "spuriously"ness occurs which must be a pretty minimal odd I will hit program failure and safely shut down anyway. I am worried by "spuriousity" thats like saying it may become sentient at it chose to reject a request when it chooses. I think the odds are minimal. Is there documentation on this pehnomenon and its frequnecy of occurence?

Share this post


Link to post
Share on other sites
And on with google the results are in on what it might mean.

Spurious \Spu"ri*ous\ (sp[=u]"r[i^]*[u^]s), a. [L. spurius.]
1. Not proceeding from the true source, or from the source
pretended; not genuine; counterfeit; false; adulterate.
[1913 Webster]

spu·ri·ous (spyr-s)
adj.
1. Lacking authenticity or validity in essence or origin; not genuine; false.

Does it mean if the system is penetrated by some means of aggressive attack perhaps? it assumes that its from a source outside of the ordinary program so I think its pretty improbable. Still its a key thing to account for thank you for the heads up on that factor!

Perhaps it refers to the task manager shutting down the program or the compile overriding the action? it sounds like abit of a mute point as anything can be supriously stepped out of by that means.

Share this post


Link to post
Share on other sites
No, it just means that OSs aren't reliable about putting threads to sleep until a condition is met, so you've got to enforce this yourself. It might wake up when the condition is met, or it might just wake up anyway (i.e. it means there are false-positives in the system, but not false-negatives).

You shouldn't just pretend it's not going to happen, or that it doesn't matter if it does happen occasionally.

This is one reason why it's designed so you must acquire a lock before waiting (and automatically acquire again after waiting) -- you can use that lock to protect an actual variable that you use to decide if waiting is over or not.

Think of wait like an optimisation-hint, but not a strong guarantee. You could just write a spin loop that repeatedly locks a mutex, checks the variable and unlocks the mutex -- but wait is an optimisation that tries to give spare cycles to the OS.

Share this post


Link to post
Share on other sites
I will design a means of cycling until it is met so long as notify one is garunteed to notify something if there is a thread in a wait state this shouldn't be a show stopping issue.

I think I have gathered enough info to continue. Still curious why there wasn't a get total_count method to begin with for the condition variable it seems like a sensible thing to have if it can be shared.

Share this post


Link to post
Share on other sites
Quote:
Original post by EnlightenedOne
The issue is that the notify function can notify when the boolean is changed before the other thread actually goes into the wait mechanism and is added to the list of threads waiting on the semaphore. I cant obviously change the values in the midst of going into wait with a timed lock because on wait any timed processes the thread had going are also set to wait.
I've read back over the thread, and the solution to the above issue seems to be: don't unlock your mutex before calling wait - then the counter, the boolean, the call to wait, and the call to notify are all atomic/mutually-exclusive.
	void waitUntilAllReady()
{
lock_guard lock(mutAccessData);
while (boolIsSceneReady == false)
{
intThreadsCaughtCountPost++;
multiThreadLinkReady.wait(mutAccessData);
intThreadsCaughtCountPost--;
}
}
void wakeUpIfAllReady()
{
lock_guard lock(mutAccessData);
if (intThreadsCaughtCountPost >= TOTALTHREADSLOADINGSCENE)
{
multiThreadLinkReady.notify_all();
boolIsSceneReady = true;
}
}

Share this post


Link to post
Share on other sites
You lock on the wait function your logic then calls this.

 	
void wakeUpIfAllReady()
{
lock_guard lock(mutAccessData);
if (intThreadsCaughtCountPost >= TOTALTHREADSLOADINGSCENE)
{
multiThreadLinkReady.notify_all();
boolIsSceneReady = true;
}
}



lock_guard lock(mutAccessData);

The bold line will never be passed as deadlock occurs and your program is frozen dead. mutAccessData is not a shared mutex.

Share this post


Link to post
Share on other sites
There's no deadlock and the mutex doesn't need to be shared for the purposes of the counter and the boolean. When you call wait, the mutex is unlocked for the duration of the wait:
Quote:
Atomically call lock.unlock() and blocks the current thread.

When the thread is unblocked (for whatever reason - i.e. spuriously or not), the lock is reacquired by invoking lock.lock() before the call to wait returns. The
^This is the key to the wait function - when you call wait, the unlock and the actual sleeping are one atomic operation, so you can ensure the boolean isn't set to true at the same time as going into a wait. The boolean can only be set to true while all threads are waiting. The line you marked bold won't be passed unless:
A) All your worker threads have called wait.
B) Any of your worker threads haven't called waitUntilAllReady yet (in which case the if will fail and wakeUpIfAllReady will return with no effect).

Share this post


Link to post
Share on other sites
ah that does change the game plan. Thanks for your input sorry I was abit slow to catch on there I had the feeling my intention had been lost in my explanation but this is definetely useful! I will update you on how things go when I rewrite this class.

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