Author: Hristo
Date: 00:04:38 12/01/03
Go up one level in this thread
On December 01, 2003 at 02:41:28, Tony Werten wrote:
>When my masterthread is spinning, waiting for results from it's workers threads,
>how do I keep it from burning CPU time ?
>
>The apifunction sleep() doesn't some threadsafe, suspending the thread and
>having it resumed by the worker seems overly complicated. ( Accept maybe if I
>can use a callback function )
>
>Any thoughts ?
>
>Tony
Use mutexes. No other way around it.
You still need to structure your code correctly but the classes bellow will
allow you to do the following:
#include "NILock.h"
NILock haveResults(0,0);
void mainThreadProc(){
while(true){
if (haveResults.lock(1000)){
You got results, since someone unlocked the haveResults
}else{
After a 1000 ms you have no results. Perhaps you can do something else.
}
}
}
void workerThreadProc(){
while(true){
Do something.
If you have results.
haveResults.unlock();
After this the mainThreadProc will awake ... eventually
}
}
Please feel free to use the source code as you wish.
source for NILock.h:
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <semaphore.h>
#include <iostream>
#include "NIDefinitions.h"
#include "NITime.h"
/**
* Need to add simple mutex wrepper object for the simplest possible
lock/unlock
* Need to add Pulse like object for use to wakeup waiting objects, without
having
* to use it for locking/unlocking semantics. "If there is Pulse; they wake-up."
*
*/
class NISemaphore{
public:
/** */
NISemaphore()
{
pthread_mutex_init(&m_mut, 0);
}
/** */
~NISemaphore()
{
pthread_mutex_destroy(&m_mut);
}
/** */
inline void lock()
{ pthread_mutex_lock(&m_mut); }
/** */
inline void unlock()
{ pthread_mutex_unlock(&m_mut); }
/** */
inline NIBool tryLock()
{ return (pthread_mutex_trylock(&m_mut) != 0); }
private:
pthread_mutex_t m_mut;
};
/**
* General purpose Lock (semaphore,mutex) interface
* If there is a timeout for the lock then it is possible that
* the lock will never be successful. Part of how things seem to work on unix.
*
* @author Hristo Doichev
* @version 0.1
*/
class NILock{
public:
/**
* create a single semaphore.
*
* @param initial determines the initial state of the semaphore.
* 0 the semaphore is created and locked immediately.
* 1 the semaphore is not locked within the constructor.
* @return
*/
explicit NILock(NIUInt_32 initial):
m_conVar(initial),
m_maxLocks(1)
{
if (m_conVar > m_maxLocks){
m_conVar = m_maxLocks;
}
pthread_mutex_init(&m_mut, 0);
pthread_cond_init(&m_con, 0);
}
/**
* create a counting Semaphore.
*
* @param initial determines the amount of locks that can be applied to
this semaphore
* after the cnstruction.
* 0 the semaphore is completely locked.
* n <= _max is the number of loks that can be applied
* @param maxLocks the maximum number of locks this semaphore can take
*
* @return
*/
explicit NILock(NIUInt_32 initial, NIUInt_32 maxLocks):
m_conVar(initial),
m_maxLocks(maxLocks)
{
pthread_mutex_init(&m_mut, 0);
pthread_cond_init(&m_con, 0);
if (m_conVar > m_maxLocks) {
m_conVar = m_maxLocks;
}
}
virtual ~NILock(){
pthread_mutex_destroy(&m_mut);
pthread_cond_destroy(&m_con);
}
/**
* return true if it is locked.
*/
virtual NIBool check(){
NIBool itIsLocked;
pthread_mutex_lock(&m_mut);
if (m_conVar > 0) {
itIsLocked = NIFalse;
}else{
itIsLocked = NITrue;
}
pthread_mutex_unlock(&m_mut);
return itIsLocked;
}
/** wait forever until lock is acquired */
virtual void lock(){
int status=0;
pthread_mutex_lock(&m_mut);
while (evaluateConditional() == NIFalse){
while ((status = pthread_cond_wait(&m_con, &m_mut)) != 0)
;
}
if (status == 0){
pthread_mutex_unlock(&m_mut);
}
}
virtual void unlock(){
pthread_mutex_lock(&m_mut);
++m_conVar;
if (m_conVar > m_maxLocks) {
m_conVar = m_maxLocks;
}
pthread_cond_signal(&m_con);
pthread_mutex_unlock(&m_mut);
// allow others to get to the lock if waiting.
sched_yield(); // This is not absolutely necessary
}
/**
* This is the most complicatied of all NILock functions.
* The general unix pthread library does not support timeouts on
* mutexes and therefore we need to use conditional variables.
* However, the conditional variables do not guarantee smooth
* execution. There are many conditions which can cause problems.
*
* @parameters timeOut in ms
*/
virtual NIBool lock(NIUInt_32 desiredTimeOut){
NIBool gotLock = NIFalse;
NIUInt_32 status = 0;
struct timespec timeout;
struct timeval startTime;
// lock the mutex so we can check the predicate
pthread_mutex_lock(&m_mut);
// if someone has the predicate then wait on the condition variable
TRY_TO_WAIT:
if (m_conVar == 0) {
gettimeofday(&startTime,0);
//std::cout << " sec: " << startTime.tv_sec << ", usec: " <<
startTime.tv_usec << std::endl;
NIUInt_32 secDelta = desiredTimeOut/1000;
timeout.tv_sec = startTime.tv_sec + (secDelta);
timeout.tv_nsec = startTime.tv_usec +
(desiredTimeOut-(secDelta*1000))*1000;
//cout << "> sec: " << timeout.tv_sec << ", usec: " <<
timeout.tv_nsec << endl;
status = pthread_cond_timedwait(&m_con, &m_mut, &timeout);
}
switch (status){
case 0:{
if (evaluateConditional()){
gotLock = true;
}else{
NIUInt_32 tempTime = (time(0) - timeout.tv_sec);
if ((desiredTimeOut/1000) > tempTime ) {
desiredTimeOut -= (tempTime*1000);
//cout << " retry lock( " << _time_out << " )" << endl;
goto TRY_TO_WAIT;
}
}
}break;
//
default:
case EINVAL:
case ETIMEDOUT:{
gotLock = false;
}break;
}
// unlock the mutex so others can do their job (and wait)
if (status != EINVAL){
pthread_mutex_unlock(&m_mut);
}
return gotLock;
}
protected:
/** evaluate the conditional variable and change it's state
* This function should be called only after a lock is acquired on the
conditional variable.
* @return true if the Condition is true.
*/
virtual NIBool evaluateConditional(){
if (m_conVar > 0) {
--m_conVar;
return NITrue;
}
return NIFalse;
}
protected:
pthread_mutex_t m_mut;
pthread_cond_t m_con;
NIInt_32 m_conVar;
NIInt_32 m_maxLocks;
};
This page took 0 seconds to execute
Last modified: Thu, 15 Apr 21 08:11:13 -0700
Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.