If you make a multi threaded application, you probably will need to synchronize the threads, e.g. if you have a list where only one thread can access it at the time. You can do this by using different synchronize objects. At the moment, there are created 4 synchronize classes and these are: PSemaphore, PMutex, PEvent and PSWMRLocker.
This chapter will not describe the difference between the different object, except for the PSWMRLocker, because this is a very special class.
The classes are designed so they are very similar to use. They all derives from a pure virtual class called PSync, except for the PSWMRLocker class. The PSync class have a Lock() and a Unlock() function. These functions are used to lock and unlock the synchronize object regardless what kind of object you use.
The PSemaphore and PMutex classes tracks which thread that has locked the object. The same thread can make multiple calls to the Lock() function without blocking. You just need the same amount of calls to Unlock() before the object will be released. This behaviour can be disabled in the constructor if you need to do that.
This is a very special kind of locker. The SWMR stands for Single Write, Multiple Read. That means if you e.g. have a list or other data you want more than one thread to read from but only one thread to write to it at the same time, you can use this class.
You don't use it the same way as you use the other classes. If you want write access, you call the WaitToWrite() function. When you're done writing, you need to call the DoneWriting() function.
You need to do the same thing when reading. The functions are then called WaitToRead() and DoneReading().
Derived from: PSync
Declared in: PSynchronize.h
PSemaphore(uint32 count = 1, bool lockSameThread = false); throw(PSystemException);
The constructor will create a semaphore and initialize it with the start count given. The count is the number of threads which can acquire the semaphore at the same time. If you don't want the same thread can aquire the semaphore multiple times by calling the Lock() function, set the lockSameThread argument to true.
~PSemaphore()
virtual ~PSemaphore(void);
Deletes the semaphore.
PSyncError Lock(uint32 timeout = PSYNC_INFINITE);
This function will try to acquire the semaphore. It will first return when it got the semaphore, the timeout has timed out or an error has occurred. It will return pSyncOk if it got the semaphore, pSyncTimeout if a timeout has occurred or pSyncError if something has went wrong. That's why it very important you check the return value. You may not go into a critical section if you didn't got the semaphore. The timeout value is given in milliseconds.
Unlock()
PSyncError Unlock(void);
This function will release the semaphore. If it succeed, it will return pSyncOk, else it will return pSyncError.
Derived from: PSync
Declared in: PSynchronize.h
PMutex(bool lockSameThread = false); throw(PSystemException);
The constructor will create a mutex and initialize it. A mutex is almost the same as a semaphore, except that it only allow one thread at the time to acquire it. If you don't want the same thread can aquire the semaphore multiple times by calling the Lock() function, set the lockSameThread argument to true.
~PMutex()
virtual ~PMutex(void);
Deletes the mutex.
PSyncError Lock(uint32 timeout = PSYNC_INFINITE);
This function will try to acquire the mutex. It will first return when it got the mutex, the timeout has timed out or an error has occurred. It will return pSyncOk if it got the mutex, pSyncTimeout if a timeout has occurred or pSyncError if something has went wrong. That's why it very important you check the return value. You may not go into a critical section if you didn't got the mutex. The timeout value is given in milliseconds.
Unlock()
PSyncError Unlock(void);
This function will release the mutex. If it succeed, it will return pSyncOk, else it will return pSyncError.
Derived from: PSync
Declared in: PSynchronize.h
PEvent(bool manualReset = false, bool initialState = false); throw(PSystemException);
The constructor will create an event and initialize it. The initialState argument indicates the start state of the event. Set it to true to set the event and false to clear it. The manualReset indicates if the event is a manual or automatic event. If you set it to true, an manual event is created and all threads waiting will be signaled. You also need to call the ResetEvent() function to reset it. An automatic event will automatic reset the event after one thread has been signaled when you call the SetEvent() function. If no thread is waiting, nothing will happend.
~PEvent()
virtual ~PEvent(void);
Deletes the event.
Lock()
PSyncError Lock(uint32 timeout = PSYNC_INFINITE);
This function will wait for the event to be signaled. If the event is already signaled when you call it, it will return immediately. If the event is not set, it will first return when it got signaled, the timeout has timed out or an error has occurred. It will return pSyncOk if the event got signaled, pSyncTimeout if a timeout has occured or else it will pSyncError if something went wrong. That's why it very important you check the return value. You may not go into a critical section if you didn't got the event. The timeout value is given in milliseconds.
PSyncError ResetEvent(void);
This function will reset the event. It will return pSyncOk if the event could be reset, else it will return pSyncError.
PSyncError SetEvent(void);
This function will set the event. If the event is created as an automatic event, it will reset it again after one thread has been signaled. It will return pSyncOk if the event could be set, else it will return pSyncError.
Unlock()
PSyncError Unlock(void);
This function doesn't do anything. It will just return pSyncError.
Derived from: None
Declared in: PSynchronize.h
PSWMRLocker(void); throw(PSystemException);
The constructor will create the objects needed to make the behavior the class have.
~PSWMRLocker()
virtual ~PSWMRLocker(void);
Deletes the created objects.
PSyncError DoneReading(void);
After you have got a successful read access to the object and you're done reading, you must call this function. It will decrement the read counter and unlock the locker objects if needed. It will return pSyncOk if everything went ok, else it will return pSyncError.
PSyncError DoneWriting(void);
After you have got a successful write access to the object and you're done writing, you must call this function. It will make sure that other threads can access the object. It will return pSyncOk if everything went ok, else it will return pSyncError.
PSyncError WaitToRead(uint32 timeout = PSYNC_INFINITE);
If you want read access, you must call this function. It will check to see if other threads is writing and if so, it will wait. You can only get read access if there isn't any other threads that has locked it with write access. More than one thread can get read access at the same time, so remember to call the DoneReading() when you're done reading.
The argument is the timeout value in milliseconds or PSYNC_INFINITE if you don't want any timeout.
The return value is pSyncOk if you got the access, pSyncTimeout if the timeout has occurred or pSyncError for an error. Remember to check the return value.
PSyncError WaitToWrite(uint32 timeout = PSYNC_INFINITE);
If you want write access, you must call this function. It will check to see if other threads is writing or reading and if so, it will wait. You can only get write access if there isn't any other threads that has locked it with write or read access. There can only be one thread that can get write access at the time, so remember to call the DoneWriting() when you're done writing.
The argument is the timeout value in milliseconds or PSYNC_INFINITE if you don't want any timeout.
The return value is pSyncOk if you got the access, pSyncTimeout if the timeout has occurred or pSyncError for an error. Remember to check the return value.
AtomicDecrement()
int32 AtomicDecrement(int32 *variable);
This function will decrement the variable you give and return the result. This function make sure that only one thread access the variable at the time.
AtomicIncrement()
int32 AtomicIncrement(int32 *variable);
This function will increment the variable you give and return the result. This function make sure that only one thread access the variable at the time.
MultipleObjectsWait()
int32 MultipleObjectsWait(PSync **objects, int32 count, bool waitAll, int32 timeout = PSYNC_INFINITE);
You can use this function if you want to wait on more than one object at the time. The function can be used in two different ways, and the waitAll argument indicates how the function behaves. If the waitAll is set to true, the function will first return when it can lock all the objects or a timeout or error has occurred. If the waitAll is set to false, the function will return when it can lock one of the objects. That object number is then returned. The object number is the index into the array starting with 0.
If you got one or more of the objects, you have to unlock them by yourself, so don't forget that.
The other arguments are a pointer to an array which have pointers to all the objects you want to wait for. The count argument is the number of arguments you have and the timeout argument is the timeout value in milliseconds.