ofThread lock logistics

I apologize if this has been answered before.

I made an class that extends ofThread and I thought “wouldn’t it be cool if I could call lock from within the public member functions so that once the user starts the thread, they don’t have to worry about calling lock/unlock because it will be taken care of.”
e.g.

  
  
void FreqOutThread::threadedFunction() {  
	while (isThreadRunning()) {  
		lock();  
		update();  
		unlock();  
		sleep(1);  
	}  
}  
  
float FreqOutThread::getCurrentFreq() {  
	lock();  
	do something here...  
	unlock();  
	return something;  
}  
  
void testApp::update(){  
	float f = freqOutThread.getCurrentFreq();  
	ofSleepMillis(10);  
}  
  

But the freqOutThread hangs at the lock inside the threadedFunction (presumably a double lock situation) even though FreqOutThread::update() doesn’t ever call getCurrentFreq().

However, this works:

  
  
void FreqOutThread::threadedFunction() {  
	while (isThreadRunning()) {  
		lock();  
		update();  
		unlock();  
		sleep(1);  
	}  
}  
  
float FreqOutThread::getCurrentFreq() {  
	do something here...  
	return something;  
}  
  
void testApp::update(){  
	freqOutThread.lock();  
	float f = freqOutThread.getCurrentFreq();  
	freqOutThread.unlock();  
	ofSleepMillis(10);  
}  
  

So I’m trying to

  1. wrap my head about the difference between these two situations [also tried this->lock()]
  2. figure out how to have all locks/unlocks handled from within the object.

Cheers,
Sean

You’ve got an unlock() after the return in your getCurrentFreq(), which is probably why it’s hanging - it never get’s to the unlock() line.

You don’t have much choice with this type of lock()/unlock(). You could return a copy of a local variable…

float FreqOutThread::getCurrentFreq() {
float n = 0;
lock();
n = 0.1; // this will probably be a dynamic value
unlock();
return n;
}

Otherwise I wouldn’t really

I should mention, primitives are generally threadsafe when reading. So you could just call the below and not worry about lock/unlock from your update function either.

float FreqOutThread::getCurrentFreq() {
return 0.1;
}

Sorry, my example was lacking…
I fixed it.

Thanks for your thoughtful reply, but I think the underlying problem has something to do with calling freqOutThread.lock() from within testApp::update() blocks the main thread while waiting for freqOutThread to unlock, but calling lock() from FreqOutThread::getCurrentFreq() doesn’t block and instead puts a double lock on freqOutThread, which then cannot be unlocked.

Your first example is correct now- i would probably still ditch the extra lock/unlock from getCurrentFreq, but it depends on what’s happening in the ‘do something’ line. Also, there should be no double lock situation as calling lock already checks it it was previously locked (it also returns a boolean, so you could call if(lock()) to see if it worked). And you are right, you would never call lock/unlock from the testApp (2nd example)- this defeats the purpose of threading as it would block your main thread.

It shouldn’t be hanging now, but it depends on what your doing in the ‘do something’ line? Maybe if you explain what’s happening there, I can figure out what’s causing the hang.

I just recently discovered another threading trick which would also solve this problem (posting here as reference).

You can use a scoped lock inside your thread with the built in ‘Poco::ScopedLock’. For example, here is a getter inside a threaded class:

  
  
int MyThreadedClass::getMyValue() {    
   Poco::ScopedLock<ofMutex> lock(mutex);  
   return myValue;  
}  
  

2 Likes

oooh, that’s interesting. Thanks Trent!
-Sean