multithreading on OSX


 
Thread Tools Search this Thread
Top Forums Programming multithreading on OSX
# 1  
Old 06-21-2008
multithreading on OSX

Hi all, I have a query about multithreading. What I would like to do is, at the start of my main update() function, start a couple of threads in parallel, once they are all complete carry on with my main update function.

Code:
void update() {
   thread1->update();  // fluid solver
   thread2->update();  // particle system
   thread3->update();  // camera1 optical flow
   thread4->update();  // camera2 optical flow
   // all of the above threads have their own data and work independantly

   etc.
   .
   .. wait till all the above threads are done.
   .. once they are done, feed the data from each of them into other ones
   .. e.g. fluid velocity info is added to particle systems reedy for next frame's update
   .. e.g. camera optical flow data is fed into fluid solver, ready for next frame's update
   
   render all
}

I am having trouble getting this working the way I want. I don't want my threads to loop continuously independent of my main update loop, I want them all to start at the beginning of my update loop, and then once they are all finished, feed the data around, then render, then repeat.

I tried creating a thread every update loop which runs only once (no while() in the function) - it works and behaves fine for a few minutes, then the threads just stop being created - no crash or hang, just no updates from threads. I also tried using an infinte while() but with a flag that determined whether the code ran that frame or not, and only set that flag at the beginning of the main update loop (code for this below) - that one is very stable, but behaviour was weird, I think the thread updates weren't being called when I wanted them to.

I've read a lot of documentation on multithreading in general and all the pthread commands. I understand the fundamentals of protecting data and all that.. but I'm just lacking a lot of experience and strategy .. so any suggestions welcome!


This is my thread class I'm using which has the infinite loop in the threaded function, but only runs the update function if the flag is set. I initialize the flag at the beginning of each main update with thread1->runOnce(); thread2->runOnce(); etc.... but it doesn't run smoothly.

Code:
#include "ofxThread.h"

class MSAThread : public ofxThread {

	bool bHasRunThisFrame;
	bool bAutoLoop;
	int interval;

public:

	// create the thread, if autoLoop is true, start running straight away and loop, 
	// otherwise wait for the runOnce command
	void start(int frameRate = 30, bool initAutoLoop = false){	
		interval = 1000/frameRate;
		bAutoLoop = initAutoLoop;
		if(!bAutoLoop) bHasRunThisFrame = true;		// don't run straight away
		startThread(true, false);   // blocking, verbose
	}
	
	// run the update function once in another thread
	void runOnce() {					
		if(lock()) {
			bAutoLoop = false; 
			bHasRunThisFrame = false;
			unlock();
		}
	}

	// run the update function in another thread
	void threadedFunction() {						
		while(isThreadRunning()) {
			if( lock() ){
				if(bAutoLoop || !bHasRunThisFrame) {
					update();
					bHasRunThisFrame = true;
					unlock();
					ofSleepMillis(interval); 
				} else {
					unlock();
				}
			}
		}
	}
	
	// main thread waits for the update function to finish 
	void waitForFinish() { if(lock()) { unlock(); } }	
	
	// this is the function that gets overvidden
	virtual void update() = 0;							
};

and it's based on this OpenFrameworks class:
Code:
class ofxThread{

	public:
		ofxThread();
		virtual ~ofxThread();
		bool isThreadRunning();
		void startThread(bool _blocking = true, bool _verbose = true);
		bool lock();
		bool unlock();
		void stopThread();

	protected:

		//-------------------------------------------------
		//you need to overide this with the function you want to thread
		virtual void threadedFunction(){
			if(verbose)printf("ofxThread: overide threadedFunction with your own\n");
		}

		//-------------------------------------------------

		#ifdef TARGET_WIN32
			static unsigned int __stdcall thread(void * objPtr){
				ofxThread* me	= (ofxThread*)objPtr;
				me->threadedFunction();
				return 0;
			}

		#else
			static void * thread(void * objPtr){
				ofxThread* me	= (ofxThread*)objPtr;
				me->threadedFunction();
				return 0;
			}
		#endif


	#ifdef TARGET_WIN32
			HANDLE            myThread;
			CRITICAL_SECTION  critSec;  	//same as a mutex
	#else
			pthread_t        myThread;
			pthread_mutex_t  myMutex;
	#endif

	bool threadRunning;
	bool blocking;
	bool verbose;
};


//-------------------------------------------------
ofxThread::ofxThread(){
	threadRunning = false;
}

//-------------------------------------------------
ofxThread::~ofxThread(){
	stopThread();
}

//-------------------------------------------------
bool ofxThread::isThreadRunning(){
	//should be thread safe - no writing of vars here
	return threadRunning;
}

//-------------------------------------------------
void ofxThread::startThread(bool _blocking, bool _verbose){

	//have to put this here because the thread can be running
	//before the call to create it returns
	threadRunning	= true;

	#ifdef TARGET_WIN32
		InitializeCriticalSection(&critSec);
		myThread = (HANDLE)_beginthreadex(NULL, 0, this->thread,  (void *)this, 0, NULL);
	#else
		pthread_mutex_init(&myMutex, NULL);
		pthread_create(&myThread, NULL, thread, (void *)this);
	#endif

	blocking		=	_blocking;
	verbose			= _verbose;
}

//-------------------------------------------------
//returns false if it can't lock
bool ofxThread::lock(){
	if(!threadRunning){
		if(verbose)printf("ofxThread: need to call startThread first\n");
		return false;
	}

	#ifdef TARGET_WIN32
		if(blocking)EnterCriticalSection(&critSec);
		else {
			if(!TryEnterCriticalSection(&critSec)){
				if(verbose)printf("ofxThread: mutext is busy \n");
				return false;
			}
		}
		if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
	#else

		if(blocking){
			if(verbose)printf("ofxThread: waiting till mutext is unlocked\n");
			pthread_mutex_lock(&myMutex);
			if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
		}else{
			int value = pthread_mutex_trylock(&myMutex);
			if(value == 0){
				if(verbose)printf("ofxThread: we are in -- mutext is now locked \n");
			}
			else{
				if(verbose)printf("ofxThread: mutext is busy - already locked\n");
				return false;
			}
		}
	#endif

	return true;
}

//-------------------------------------------------
bool ofxThread::unlock(){

	if(!threadRunning){
		if(verbose)printf("ofxThread: need to call startThread first\n");
		return false;
	}

	#ifdef TARGET_WIN32
		LeaveCriticalSection(&critSec);
	#else
		pthread_mutex_unlock(&myMutex);
	#endif

	if(verbose)printf("ofxThread: we are out -- mutext is now unlocked \n");

	return true;
}

//-------------------------------------------------
void ofxThread::stopThread(){
	if(threadRunning){
		#ifdef TARGET_WIN32
			CloseHandle(myThread);
		#else
			pthread_mutex_destroy(&myMutex);
			pthread_detach(myThread);
		#endif
		if(verbose)printf("ofxThread: thread stopped\n");
		threadRunning = false;
	}else{
		if(verbose)printf("ofxThread: thread already stopped\n");
	}
}

# 2  
Old 06-21-2008
I could see two possible problems,

controlling the behavior ( which we are interested ) with a variable which is certainly not in context for the segments of the program, in such a case there is no need for the threads to branch out ( obey ) execution based on the value of the boolean variables

another thing that I could smell is, the possibility of mutual lock ( am guessing it ) where it just runs fine for a instant ' t ' units of time after that gets into the mutual lock condition.

Is the behavior of working fine for few minutes and receiving no updates a constant behavior ? I mean is it happening at 'nth' instant of time each time? If so, my assumption might be wrong - else there is a possibility

One more question, ( sorry if its silly ) do you check/validate the creation of threads ? Since its running in an infinite loop, conditions might go wrong and outbursting with the maximum number of threads that can be created.
# 3  
Old 06-21-2008
Hi, thanks for the response.

Quote:
One more question, ( sorry if its silly ) do you check/validate the creation of threads ? Since its running in an infinite loop, conditions might go wrong and outbursting with the maximum number of threads that can be created.
I think something like that was happening when I went down the 'create a new thread every loop' approach, which is why I scrapped that idea and went for the 'infinite loop in the thread, but only run the update function when the variable is set' approach.

I think I've actually identified the problem. I think it was the sleep() function in my thread loop. I understand why I need that if the loop is continuously running and doing heavy stuff, but do I need it in my case?

When I comment out the sleep line (As below), the behaviour looks a lot smoother and correct, maybe because as soon as I set the bHasRunThisFrame flag in the thread instance to false, the update function is called almost immediately (which is what I want), whereas with the sleep() function, maybe there was a delay of upto interval before the update kicked in?.... or something :P Is it bad to not have a sleep function in there?

// run the update function in another thread
Code:
void MSAThread::threadedFunction() {						
	while(isThreadRunning()) {
		if( lock() ){
			if(bAutoLoop || !bHasRunThisFrame) {
				update();
				bHasRunThisFrame = true;
				unlock();
//				ofSleepMillis(interval); 
			} else {
				unlock();
			}
		}
	}
}

# 4  
Old 06-26-2008
OT: A Helpful Class

I've been out of the game for a while with C++ but as I read your post, I was reminded of some classes I wrote to manage multiple threads. Also, Bartosz Milewski of Reliable Software - Creators of the distributed version control system, Code Co-op wrote a really cool critical section class wrapper that totally protects against accidentally leaving a lock in place. His discussion of how resource management is the key to reliable message driven software was well done and he had numerous ways to protect against leaving resources open or laying around that would cause memory leaks or hangs. Here it is:
Code:
// CriticalSection.h
// 
// A class using Resource Management technique(RM: see 
// http://www.relisoft.com/resource/resource.html for
// discussion) to handle critical section code that 
// guarantees no memory leaks or open locks.
//
// Revision Log
//
// Date       Who SAR     Notes
// ========== === ======= =====================================
//                        (c) Reliable Software, 1997, 98
//                        Bartosz Milewski, www.relisoft.com
// 

#ifdef SAMPLE_CODE

   // somewhere with the resource to protect
   CCriticalSection _critSect;

   // later in the code...
   {
      CLock lock(_critSect);
      // perform action which may throw
      myVar += 10;
      // guaranteed automatic destructor of lock
      // when it goes out of scope
   }
}
#endif


#ifndef RFC_CRITICAL_SECTION_H
#define RFC_CRITICAL_SECTION_H

#include <windows.h>

class CCriticalSection
{
   friend class CLock;
public:
   CCriticalSection() { InitializeCriticalSection(&_critSectStruct); }
   ~CCriticalSection() { DeleteCriticalSection(&_critSectStruct); }
private: 
   // these must only be used by CLock object, never directly
   void Enter() { EnterCriticalSection(&_critSectStruct); }
   void Leave() { LeaveCriticalSection(&_critSectStruct); }

   CCriticalSection(CCriticalSection& o); // not allowed
   CCriticalSection& operator=(CCriticalSection& o); // not allowed

   CRITICAL_SECTION _critSectStruct;
};

class CLock 
{
public:
    CLock(CCriticalSection& critSect) 
        : _critSectObj(critSect) 
    {
        _critSectObj.Enter();
    }
    ~CLock()
    {
        _critSectObj.Leave();
    }
private:
    CCriticalSection & _critSectObj;
};

#endif

Login or Register to Ask a Question

Previous Thread | Next Thread

9 More Discussions You Might Find Interesting

1. Programming

Help with multithreading

I take this question of the The Linux Programming Interface: A Linux and Unix System Programming page 652 exercise 30.1 I want someone to explain the under line statement because it sounds complex to me couldn't understand anything 30-1 Modify the program (thread_incr.c) so that each loop in... (3 Replies)
Discussion started by: fwrlfo
3 Replies

2. What is on Your Mind?

Alarm interrupt and multithreading

Hi Friends any know how became a friend in this Android Programming Language (0 Replies)
Discussion started by: ljarun
0 Replies

3. Programming

Multithreading in reading file

Dear all, I am having a huge XML file, as below structure <EMPLOYEE> <RECORD id =aaa> <Salary>99999</Salary> <section>ssss</section> </RECORD> <RECORD id =bbb> <Salary>77777</Salary> <section>ssss</section> </RECORD> </EMPLOYEE> This is a 50 GB file I want to read this file in... (9 Replies)
Discussion started by: arunkumar_mca
9 Replies

4. Programming

how to do udp broadcast with multithreading

hello to all i want to use multithreading to my UDP broadcast server client program. will anyone help me by proving C code. i am working in fedora. also my requirement is POSIX compliance.please help me..... (6 Replies)
Discussion started by: moti12
6 Replies

5. IP Networking

how to do udp broadcast with multithreading

hello to all i want to use multithreading to my UDP broadcast server client program. will anyone help me by proving C code. i am working in fedora. also my requirement is POSIX compliance.please help me..... (0 Replies)
Discussion started by: moti12
0 Replies

6. Programming

MultiThreading using Pthreads

Situation: i have multiple pthread_create calls like this: pthread_create(...., ThreadFunc1,.....); pthread_create(...., ThreadFunc2,.....); . . which i am using to create multiple threads.All the "ThreadFunc<i>" functions are actually calling same function "Receive" of a class using same... (3 Replies)
Discussion started by: Sastra
3 Replies

7. Shell Programming and Scripting

Multithreading program

Hi I need to insert 1million records into MySQL database, but it is taking lot of time as there is no bulk insert support. I want to spawn 10 processes which will insert 100k records each parallely. Can somebody help me with a example program to execute this task through shell scripting. (5 Replies)
Discussion started by: sach_roger
5 Replies

8. UNIX for Advanced & Expert Users

multithreading in UNIX

Hi, Can you please give me a suitable reference to learn multithreading programming in C in UNIX? Thanks (3 Replies)
Discussion started by: naan
3 Replies

9. Programming

Multithreading in Pro*C

:confused: Hi! I have created a Multhreaded Application in Pro*C (using pthreads) with about 5 Threads running simultaneously. The Application is basically to Update a Centralized Table in Oracle, which updates different rows in the Table (Each Thread updates different rows!). The... (16 Replies)
Discussion started by: shaik786
16 Replies
Login or Register to Ask a Question