Multithread APIs Adam Piotrowski Grzegorz Jaboski Lecture IV
Multithread API’s Adam Piotrowski Grzegorz Jabłoński Lecture IV
Synchronisation • Mutexes • Semaphores • Condition Variables 2
Mutex The mutual exclusion lock is the simplest and most primitive synchronization variable. It provides a single, absolute owner for the section of code (thus a critical section) that it brackets between the calls to pthread_mutex_lock() and pthread_mutex_unlock(). The first thread that locks the mutex gets ownership, and any subsequent attempts to lock it will fail, causing the calling thread to go to sleep. 3
Mutex initialisation NAME pthread_mutex_init, pthread_mutex_destroy initializes mutex with attr or destroys the mutex, making it unusable in any form SYNOPSIS #include <pthread. h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); 4
Mutex unlock operation NAME pthread_mutex_unlock - unlocks mutex and wakes up the first thread sleeping on it. SYNOPSIS #include <pthread. h> int pthread_mutex_unlock(pthread_mutex_t *mutex); 5
Mutex example thread 1 thread 2 add(request_t *request) { pthread_mutex_lock(&lock); request->next = requests; requests = request pthread_mutex_unlock(&lock); } request_t *remove() { pthread_mutex_lock(&lock); . . . sleeping. . . request = requests; requests = requests->next; pthread_mutex_unlock(&lock) return(request); } 6
Mutex example 7
Semaphores A counting semaphore 6 is a variable that you can increment arbitrarily high, but decrement only to zero. A sem_post() operation increments the semaphore, while a sem_wait() attempts to decrement it. If the semaphore is greater than zero, the operation succeeds; if not, then the calling thread must go to sleep until a different thread increments it. 8
Semaphores initialisation NAME sem_init, sem_destroy - initializes the semaphore to value. If pshared is non-zero, then the semaphore will be sharable among processes. This destroys the semaphore. SYNOPSIS #include <pthread. h> int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); 9
Semaphores operations NAME sem_post, sem_wait, sem_trywait - function increments the value of the semaphore or decrements the value of sem by one. If the semaphore’s value is zero, sem_wait() blocks, waiting for the semaphore to be incremented by another process or thread, while sem_trywait() will return immediately. SYNOPSIS #include <pthread. h> int sem_post(sem_t *sem); int sem_trywait(sem_t *sem); int sem_wait(sem_t *sem); 10
Semaphores operations 11
Semaphores operations NAME sem_open, sem_close - returns a pointer to the semaphore name. All processes which call this on the same name will get the same semaphore pointer or closes the named semaphore for this process. SYNOPSIS #include <pthread. h> sem_t *sem_open(char *name, int oflag, . . . ); int sem_close(sem_t *sem); 12
Semaphors example 13
Semaphors example producer() { request_t *request; while(1) { request = get_request(); add(request); sem_post(&requests_length); } } request_t *get_request() { request_t *request; request = (request_t *) malloc(sizeof(request_t)); request->data = read_from_net(); return(request) } void process_request(request_t *request) { process(request->data); free(request); } consumer() { request_t *request; while(1){ SEM_WAIT(&requests_length); request = remove(); process_request(request); } } 14
Conditional Variables 15
Conditional Variable initialisation NAME pthread_cond_init, pthread_cond_destroy - initializes cond with att or destroys the condition variable, making it unusable in any form. SYNOPSIS #include <pthread. h> int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); int pthread_cond_destroy(pthread_cond_t *cond); 16
Conditional Variable Wait Operation NAME pthread_cond_wait, pthread_cond_timewait - atomically releases mutex and causes the calling thread to block on cond. Upon successful return, the mutex will be reacquired. SYNOPSIS #include <pthread. h> int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); 17
Conditional Variable Signal Operation NAME pthread_cond_signal, pthread_cond_broadcast - unblocks the first thread (if any) blocked on a condition variable or unblocks all threads blocked on a condition variable. You do not know the order in which they awake. SYNOPSIS #include <pthread. h> int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); 18
Conditional Variable Example thread 1 thread 2 pthread_mutex_lock(&m); while (!my_condition) pthread_cond_wait(&c, &m); . . . sleeping. . . pthread_mutex_lock(&m); my_condition = TRUE; pthread_mutex_unlock(&m); pthread_cond_signal(&c); do_thing() pthread_mutex_unlock(&m); 19
Conditional Variable Example 20
Conditional Variable Example void *producer(void *arg) { request_t *request; while(1) { request = get_request(); pthread_mutex_lock(&r_lock); while (length >= 10) pthread_cond_wait(&r_producer, &r_lock); add(request); length++; pthread_mutex_unlock(&r_lock); pthread_cond_signal(&r_consumer); } } void *consumer(void *arg) { request_t *request; while(1) { pthread_mutex_lock(&r_lock); while (length == 0) pthread_cond_wait(&r_consumer, &r_lock); request = remove(); length--; pthread_mutex_unlock(&r_lock); pthread_cond_signal(&r_producer); process_request(request); } } 21
Multithread API’s Windows OS
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process(LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 23
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, Pointer to a null-terminated string that specifies the module BOOL b. Inherit. Handles, to execute. DWORD dw. Creation. Flags, LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 24
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOLtob. Inherit. Handles, Pointer a null-terminated string that specifies the DWORD command linedw. Creation. Flags, to execute. LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 25
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, A pointer to a SECURITY_ATTRIBUTES structure that LPCTSTRwhether lp. Current. Directory, determines the returned handle can be inherited by lp. Startup. Info, child. LPSTARTUPINFO processes. LPPROCESS_INFORMATION lp. Process. Information ); 26
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, If this parameter TRUE, each inheritable handle in the LPCTSTR calling processlp. Current. Directory, is inherited by the new process. LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 27
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, LPCTSTR lp. Current. Directory, Additional creation flags e. g. CREATE_NEW_CONSOLE, LPSTARTUPINFO lp. Startup. Info, CREATE_SUSPENDED, DETACHED_PROCESS LPPROCESS_INFORMATION lp. Process. Information ); 28
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, A pointer to the environment block for the new process. LPPROCESS_INFORMATION lp. Process. Information ); 29
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 30 process. The full path to the current directory for the
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, A pointer to a STARTUPINFO LPVOID lp. Environment, LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 31
Processes NAME Create. Process - creates a new process and its primary thread. SYNOPSIS BOOL Create. Process( LPCTSTR lp. Application. Name, LPTSTR lp. Command. Line, LPSECURITY_ATTRIBUTES lp. Process. Attributes, LPSECURITY_ATTRIBUTES lp. Thread. Attributes, BOOL b. Inherit. Handles, DWORD dw. Creation. Flags, A pointer to a PROCESS_INFORMATION structure that LPVOID lp. Environment, receives identification information about the new process. LPCTSTR lp. Current. Directory, LPSTARTUPINFO lp. Startup. Info, LPPROCESS_INFORMATION lp. Process. Information ); 32
Process example void _tmain( int argc, TCHAR *argv[] ) { STARTUPINFO si; PROCESS_INFORMATION pi; if( !Create. Process( NULL, // No module name (use command line) argv[1], // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable FALSE, // Set handle inheritance to FALSE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi ) // Pointer to PROCESS_INFORMATION structure ) { printf( "Create. Process failed (%d)n", Get. Last. Error() ); return; } // Wait until child process exits. Wait. For. Single. Object( pi. h. Process, INFINITE ); // Close process and thread handles. Close. Handle( pi. h. Process ); 33 Close. Handle( pi. h. Thread ); }
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, DWORD fdw. Create, LPDWORD lp. IDThread ); 34
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOIDto lpv. Thread. Param, A pointer a SECURITY_ATTRIBUTES structure that DWORDwhether fdw. Create, determines the returned handle can be inherited by child. LPDWORD processes. lp. IDThread ); 35
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, fdw. Create, The DWORD initial size of the stack, in bytes. LPDWORD lp. IDThread ); 36
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, DWORD fdw. Create, A pointer to the application-defined function to be executed LPDWORD lp. IDThread ); by the thread and represents the starting address of the thread. DWORD Thread. Proc(LPVOID lp. Parameter ); 37
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, DWORD fdw. Create, LPDWORD lp. IDThread ); A pointer to a variable to be passed to the thread. 38
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, DWORD fdw. Create, LPDWORD lp. IDThread ); The flags that control the creation of the thread i. e. CREATE_SUSPENDED. 39
Threads NAME Create. Thread- creates a thread to execute within the address space of the calling process. SYNOPSIS HANDLE Create. Thread( LPSECURITY_ATTRIBUTES lpsa, DWORD cb. Stack, LPTHREAD_START_ROUTINE lp. Start. Addr, LPVOID lpv. Thread. Param, DWORD fdw. Create, LPDWORD lp. IDThread ); A pointer to a variable that receives the thread identifier. 40
Threads - Example int _tmain() { PMYDATA p. Data[MAX_THREADS]; DWORD dw. Thread. Id[MAX_THREADS]; HANDLE h. Thread[MAX_THREADS]; int i; for( i=0; i<MAX_THREADS; i++ ) { p. Data[i] = (PMYDATA) Heap. Alloc(Get. Process. Heap(), HEAP_ZERO_MEMORY, sizeof(MYDATA)); p. Data->val 1 = i; p. Data->val 2 = i+100; h. Thread[i] = Create. Thread( NULL, // default security attributes 0, // use default stack size My. Thread, // thread function p. Data, // argument to thread function 0, // use default creation flags &dw. Thread. Id[i]); // returns the thread identifier }} Wait. For. Multiple. Objects(MAX_THREADS, h. Thread, TRUE, INFINITE); // Close all thread handles and free memory allocation. for(i=0; i<MAX_THREADS; i++) { Close. Handle(h. Thread[i]); } Heap. Free(Get. Process. Heap(), 0, p. Data[i]); return 0; } 41
What is wrong with Create. Thread function ? A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than Create. Thread and Exit. Thread 42
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr ); 43
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned )( void * ), Pointer to (a*start_address SECURITY_ATTRIBUTES structure that void *arglist, determines whether the returned handle can be inherited by childunsigned processes. initflag, unsigned *thrdaddr ); 44
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, Stack size for a new thread or 0. unsigned initflag, unsigned *thrdaddr ); 45
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, unsigned initflag, Start address of a routine that begins execution of a new unsigned *thrdaddr ); thread. 46
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, unsigned initflag, unsigned ); to a new thread. Argument list*thrdaddr to be passed 47
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr ); Argument list to be passed to a new thread. 48
_beginthreadex NAME _beginthreadex - creates a thread to execute within the address space of the calling process. SYNOPSIS uintptr_t _beginthreadex( void *security, unsigned stack_size, unsigned ( *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr ); Points to a 32 -bit variable that receives the thread 49 identifierlist to be passed to a new thread.
_beginthreadex example int main() { HANDLE h. Thread; unsigned thread. ID; printf( "Creating second thread. . . n" ); h. Thread = (HANDLE)_beginthreadex( NULL, 0, &Second. Thread. Func, NULL, 0, &thread. ID ); Wait. For. Single. Object( h. Thread, INFINITE ); Close. Handle( h. Thread ); } 50
Exit. Thread or return • Exit. Thread is the preferred method of exiting a thread in C code. • Return is the preferred method of exiting a thread in C++ code. 51
Synchronisation • Synchronisation in user mode – Atomic access – Critical sections • Synchronisation in kernel mode – Wait functions – Mutexes – Semphores 52
SYNCHRONISATION IN USER MODE 53
Interlock functions • • • Interlocked. Add Interlocked. And Interlocked. Bit. Test. And. Reset Interlocked. Bit. Test. And. Set Interlocked. Compare. Exchange. Pointer Interlocked. Decrement Interlocked. Exchange. Add Interlocked. Exchange. Pointer Interlocked. Increment Interlocked. Or Interlocked. Xor 54
Interlock functions • Interlocked. Add • Interlocked. And • Interlocked. Bit. Test. And. Reset LONG Interlocked. Add(LONG volatile* Addend, LONG Value ); • Interlocked. Bit. Test. And. Set Performs an atomic addition operation on the specified LONG values. • Interlocked. Compare. Exchange. Pointer • Interlocked. Decrement • Interlocked. Exchange. Add • Interlocked. Exchange. Pointer • Interlocked. Increment • Interlocked. Or • Interlocked. Xor 55
Interlock functions • Interlocked. Add • Interlocked. And • Interlocked. Bit. Test. And. Reset • Interlocked. Bit. Test. And. Set • Interlocked. Compare. Exchange. Pointer • Interlocked. Decrement BOOLEAN Interlocked. Bit. Test. And. Set(LONG volatile* Base, • Interlocked. Exchange LONG Bit ); Tests the specified bit of the specified LONG value and sets • Interlocked. Exchange. Add it to 1. The operation is atomic. • Interlocked. Exchange. Pointer • Interlocked. Increment • Interlocked. Or • Interlocked. Xor 56
Interlock functions • Interlocked. Add • Interlocked. And • Interlocked. Bit. Test. And. Reset • Interlocked. Bit. Test. And. Set • Interlocked. Compare. Exchange. Pointer • Interlocked. Decrement • Interlocked. Exchange PVOID Interlocked. Compare. Exchange. Pointer(PVOID volatile* • Interlocked. Exchange. Add Destination, PVOID Exchange, PVOID Comparand ); • Interlocked. Exchange. Pointer The function compares the Destination value with the • Interlocked. Increment Comparand value. If the Destination value is equal to the • Interlocked. Or Comparand value, the Exchange value is stored in the address • Interlocked. Xor specified by Destination. Otherwise, no operation is performed. 57
Interlock functions • Interlocked. Add • Interlocked. And • Interlocked. Bit. Test. And. Reset • Interlocked. Bit. Test. And. Set • Interlocked. Compare. Exchange. Pointer • Interlocked. Decrement • Interlocked. Exchange. Add • Interlocked. Exchange. Pointer • Interlocked. Increment • Interlocked. Or • Interlocked. Xor LONG Interlocked. Increment(PLONG Addend); Increments a caller-supplied variable as an atomic operation. 58
Critical sections void Initialize. Critical. Section( LPCRITICAL_SECTION lp. Critical. Section ); Initializes a critical section object. BOOL Initialize. Critical. Section. And. Spin. Count( LPCRITICAL_SECTION lp. Critical. Section, DWORD dw. Spin. Count ); Initializes a critical section object and sets the spin count for the critical section. 59
Critical sections void Enter. Critical. Section( LPCRITICAL_SECTION p. Critical. Section ); Waits for ownership of the specified critical section object. The function returns when the calling thread is granted ownership. void Leave. Critical. Section( LPCRITICAL_SECTION lp. Critical. Section ); Releases ownership of the specified critical section object. 60
Critical sections example CRITICAL_SECTION Critical. Section; int main() { if (!Initialize. Critical. Section. And. Spin. Count(&Critical. Section, 0 x 80000400) ) return 0; . . . } // Release resources used by the critical section object. Delete. Critical. Section(&Critical. Section) DWORD Thread. Proc( LPVOID lp. Parameter ) {. . . // Request ownership of the critical section. Enter. Critical. Section(&Critical. Section); // Access the shared resource. // Release ownership of the critical section. Leave. Critical. Section(&Critical. Section); . . . } 61
SYNCHRONISATION IN KERNEL MODE 62
Wait Functions NAME Wait. For. Single. Object - Waits until the specified object is in the signaled state or the time-out interval elapses. SYNOPSIS DWORD Wait. For. Single. Object(HANDLE h. Handle, DWORD dw. Milliseconds ); 63
Wait Functions NAME Wait. For. Multiple. Objects - Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses. SYNOPSIS DWORD Wait. For. Multiple. Objects(DWORD n. Count, const HANDLE* lp. Handles, BOOL b. Wait. All, DWORD dw. Milliseconds ); 64
Close. Handle NAME Close. Handle - Closes an open object handle. SYNOPSIS BOOL Close. Handle(HANDLE h. Object ); 65
Events Objects • The event object is useful in sending a signal to a thread indicating that a particular event has occurred. 66
Event Functions • • Create. Event Open. Event Set. Event Reset. Event 67
Create. Event NAME Create. Event- Creates or opens a named or unnamed event object. SYNOPSIS HANDLE Create. Event( LPSECURITY_ATTRIBUTES lp. Event. Attributes, BOOL b. Manual. Reset, BOOL b. Initial. State, LPCTSTR lp. Name ); 68
Reset. Event NAME Reset. Event- Sets the specified event object to the nonsignaled state. SYNOPSIS BOOL Reset. Event(HANDLE h. Event ); 69
Set. Event NAME Reset. Event- Sets the specified event object to the signaled state. SYNOPSIS BOOL Set. Event(HANDLE h. Event ); 70
Event Example HANDLE gh. Global. Write. Event; HANDLE gh. Read. Events[THREADCOUNT]; DWORD Thread. Proc(LPVOID lp. Param) void Write. To. Buffer(VOID) { { DWORD dw. Wait. Result; DWORD dw. Wait. Result, i; HANDLE h. Events[2]; Reset. Event(gh. Global. Write. Event) ) h. Events[0] = *(HANDLE*)lp. Param; // thread's read event dw. Wait. Result = Wait. For. Multiple. Objects( h. Events[1] = gh. Global. Write. Event; // global write event THREADCOUNT, // number of handles in array gh. Read. Events, // array of read-event handles dw. Wait. Result = Wait. For. Multiple. Objects( TRUE, // wait until all are signaled 2, // number of handles in array INFINITE); // indefinite wait h. Events, // array of event handles TRUE, // wait till are signaled switch (dw. Wait. Result) INFINITE); // indefinite wait { case WAIT_OBJECT_0: switch (dw. Wait. Result) printf("Main thread writing to the shared buffer. . . n"); { break; case WAIT_OBJECT_0: printf("Thread %d reading from buffer. . . n", default: Get. Current. Thread. Id()); printf("Wait error: %dn", Get. Last. Error()); break; Exit. Process(0); default: } printf("Wait error: %dn", Get. Last. Error()); Set. Event(gh. Global. Write. Event); Exit. Thread(0); } for(i = 0; i < THREADCOUNT; i++) Set. Event(h. Events[0]); Set. Event(gh. Read. Events[i])); return 1; 71 } }
Semaphores NAME Create. Semaphore - Creates or opens a named or unnamed semaphore object. SYNOPSIS HANDLE Create. Semaphore( LPSECURITY_ATTRIBUTES lp. Semaphore. Attributes, LONG l. Initial. Count, LONG l. Maximum. Count, LPCTSTR lp. Name ); 72
Semaphores NAME Release. Semaphore - Increases the count of the specified semaphore object by a specified amount. SYNOPSIS BOOL Release. Semaphore( HANDLE h. Semaphore, LONG l. Release. Count, LPLONG lp. Previous. Count ); 73
Semaphore example HANDLE gh. Semaphore; void main() { HANDLE a. Thread[THREADCOUNT]; DWORD Thread. ID; int i; gh. Semaphore = Create. Semaphore( NULL, // default security attributes MAX_SEM_COUNT, // initial count MAX_SEM_COUNT, // maximum count NULL); // unnamed semaphore for( i=0; i < THREADCOUNT; i++ ) { a. Thread[i] = Create. Thread( NULL, // default security attributes 0, // default stack size (LPTHREAD_START_ROUTINE) Thread. Proc, NULL, // no thread function arguments 0, // default creation flags &Thread. ID); // receive thread identifier } Wait. For. Multiple. Objects(THREADCOUNT, a. Thread, TRUE, INFINITE); for( i=0; i < THREADCOUNT; i++ ) Close. Handle(a. Thread[i]); Close. Handle(gh. Semaphore); } DWORD WINAPI Thread. Proc( LPVOID lp. Param ) { DWORD dw. Wait. Result; BOOL b. Continue=TRUE; while(b. Continue) { dw. Wait. Result = Wait. For. Single. Object( gh. Semaphore, // handle to semaphore 0 L); // zero-second time-out interval switch (dw. Wait. Result) { case WAIT_OBJECT_0: b. Continue=FALSE; Sleep(5); Release. Semaphore( gh. Semaphore, // handle to semaphore 1, // increase count by one NULL) ); // not interested in previous count break; case WAIT_TIMEOUT: break; } } return TRUE; } 74
Mutex NAME Create. Mutex- Creates or opens a named or unnamed mutex object. SYNOPSIS HANDLE Create. Mutex( PSECURITY_ATTRIBUTES lp. Mutex. Attributes, BOOL b. Initial. Owner, LPCTSTR lp. Name ); 75
Mutex NAME Release. Mutex - Releases ownership of the specified mutex object. SYNOPSIS BOOL Release. Mutex(HANDLE h. Mutex ); 76
Mutex example HANDLE gh. Mutex; void main() { HANDLE a. Thread[THREADCOUNT]; DWORD Thread. ID; int i; gh. Mutex = Create. Mutex( NULL, // default security attributes FALSE, // initially not owned NULL); // unnamed mutex for( i=0; i < THREADCOUNT; i++ ) { a. Thread[i] = Create. Thread( NULL, // default security attributes 0, // default stack size (LPTHREAD_START_ROUTINE) Write. To. Database, NULL, // no thread function arguments 0, // default creation flags &Thread. ID); // receive thread identifier } Wait. For. Multiple. Objects(THREADCOUNT, a. Thread, TRUE, INFINITE); for( i=0; i < THREADCOUNT; i++ ) Close. Handle(a. Thread[i]); Close. Handle(gh. Mutex); } DWORD WINAPI Write. To. Database( LPVOID lp. Param ) { DWORD dw. Count=0, dw. Wait. Result; while( dw. Count < 20 ) { dw. Wait. Result = Wait. For. Single. Object( gh. Mutex, // handle to mutex INFINITE); // no time-out interval switch (dw. Wait. Result) { case WAIT_OBJECT_0: __try { printf("Thread %d writing to database. . . n", Get. Current. Thread. Id()); dw. Count++; } __finally { if (! Release. Mutex(gh. Mutex)) { // Deal with error. } } break; case WAIT_ABANDONED: return FALSE; } } return TRUE; } 77
Advanced Thread Objects • Thread pools • Fibers 78
Thank You
- Slides: 79