multithreading programming
DESCRIPTION
Multithreading Programming. Yung-Pin Cheng. History. In the past (TRANSCRIPT
Multithreading Multithreading ProgrammingProgramming
Yung-Pin ChengYung-Pin Cheng
HistoryHistory
In the past (<10 years), when there was In the past (<10 years), when there was no multithreading support from O.S., how no multithreading support from O.S., how a server (such as telnet, BBS server) is a server (such as telnet, BBS server) is implemented? implemented? The era of multi-process programmingThe era of multi-process programming
Unix’s Unix’s fork()fork() revisited revisited
An example of Unix fork()An example of Unix fork()
void main() { printf(“hello”); fork(); printf(“bye”);}
hellobyebye
The output
How How fork()fork() is implemented in Unix? is implemented in Unix?
Process’s Image in Memory
void main() { printf(“hello”); fork(); printf(“bye”);}
_TEXT(code)
_DATA(code)
PC(Programcounter)
void main() { printf(“hello”); fork(); printf(“bye”);}
_TEXT(code)
_DATA(code)
PC(Programcounter) copy
fork()fork() example again example again
void main() { if (fork() == 0) printf(“ in the child process”); else printf(“ in the parent process”);}
An old-fashioned concurrent serverAn old-fashioned concurrent server
main() {main() {// create a TCP/IP socket to use// create a TCP/IP socket to uses =s =socketsocket(PF_INET,SOCK_STREAM ,0);(PF_INET,SOCK_STREAM ,0);
// bind the server address// bind the server addressZ =Z = bind bind(s, (struct sockaddr *)&adr_srvr, len_inet);(s, (struct sockaddr *)&adr_srvr, len_inet);
// make it a listening socket// make it a listening socketZ = Z = listenlisten(s, 10);(s, 10);
// start the server loop// start the server loopfor (;;) {for (;;) { // wait for a connect // wait for a connect c = c = acceptaccept(s, (struct sockaddr*) &adr_clnt,& le(s, (struct sockaddr*) &adr_clnt,& le
n_int);n_int);
PID = fork();PID = fork(); if (PID > 0) {if (PID > 0) { // parent process// parent process close(c);close(c); continue ; continue ; }} // child process // child process rx = fdopen(c,”r”);rx = fdopen(c,”r”); tx = fdopen(dup(c), “w”);tx = fdopen(dup(c), “w”);
// process client’s request// process client’s request …… …….... fclose(tx); fclose(rx);fclose(tx); fclose(rx); exit(0);exit(0);}}
Problems with old-fashioned multi-Problems with old-fashioned multi-processes programmingprocesses programming
Context switching overhead is highContext switching overhead is highCommunications between forked processeCommunications between forked processes also has high costs also has high cost typical mechanism – via typical mechanism – via IPC (interprocess coIPC (interprocess co
mmunication)mmunication) such as such as shared memory, semapshared memory, semaphore, message queuehore, message queue
these are cross address space communicatiothese are cross address space communicationn
invoking of IPC cause mode switch – invoking of IPC cause mode switch – may caumay cause a process to block.se a process to block.
The concept of a The concept of a processprocessHowever, processes are still the very basic However, processes are still the very basic element in O.S.element in O.S. UNIT of resources ownershipUNIT of resources ownership
Allocated with virtual address space + control of other Allocated with virtual address space + control of other resources such as I/O, files….resources such as I/O, files….
Unit of dispatchingUnit of dispatchingAn execution paths (may interleaved with other An execution paths (may interleaved with other processes)processes)An execution state, dispatching priority.An execution state, dispatching priority.Controlled by OSControlled by OS
Now, What is a thread?Now, What is a thread?
A thread is an execution path in the code A thread is an execution path in the code segmentsegmentO.S. provide an individual Program O.S. provide an individual Program Counter (PC) for each execution pathCounter (PC) for each execution path
An exampleAn example
main() {main() {// create a TCP/IP socket to use// create a TCP/IP socket to uses =s =socketsocket(PF_INET,SOCK_STREAM ,0);(PF_INET,SOCK_STREAM ,0);
// bind the server address// bind the server addressZ =Z = bind bind(s, (struct sockaddr *)&adr_srvr, len_inet);(s, (struct sockaddr *)&adr_srvr, len_inet);
// make it a listening socket// make it a listening socketZ = Z = listenlisten(s, 10);(s, 10);
// start the server loop// start the server loopfor (;;) {for (;;) { // wait for a connect // wait for a connect c = c = acceptaccept(s, (struct sockaddr*) &adr_clnt,& le(s, (struct sockaddr*) &adr_clnt,& le
n_int);n_int);
PID = fork();PID = fork(); if (PID > 0) {if (PID > 0) { // parent process// parent process close(c);close(c); continue ; continue ; }} // child process // child process rx = fdopen(c,”r”);rx = fdopen(c,”r”); tx = fdopen(dup(c), “w”);tx = fdopen(dup(c), “w”);
// process client’s request// process client’s request …… …….... fclose(tx); fclose(rx);fclose(tx); fclose(rx); exit(0);exit(0);}}
PC
CommentsComments
Traditional program is one thread per Traditional program is one thread per process.process.The main thread starts with The main thread starts with main()main()Only one thread (or, program counter) is Only one thread (or, program counter) is allowed to execute the code segmentallowed to execute the code segmentTo add a new PC, you need to To add a new PC, you need to fork() fork() to to have another PC to execute have another PC to execute in another in another process address space.process address space.
MultithreadingMultithreading
The ability of an OS to support multiple thrThe ability of an OS to support multiple threads of execution within a single process eads of execution within a single process (many program counters in a code segme(many program counters in a code segment)nt)Windows support multithreading earlier (miWindows support multithreading earlier (mid 1990)d 1990)SunOS, Linux came lateSunOS, Linux came late
The example againThe example again
main() {main() {// create a TCP/IP socket to use// create a TCP/IP socket to uses =s =socketsocket(PF_INET,SOCK_STREAM ,0);(PF_INET,SOCK_STREAM ,0);
// bind the server address// bind the server addressZ =Z = bind bind(s, (struct sockaddr *)&adr_srvr, len_inet);(s, (struct sockaddr *)&adr_srvr, len_inet);
// make it a listening socket// make it a listening socketZ = Z = listenlisten(s, 10);(s, 10);
// start the server loop// start the server loopfor (;;) {for (;;) { // wait for a connect // wait for a connect c = c = acceptaccept(s, (struct sockaddr*) &adr_clnt,& le(s, (struct sockaddr*) &adr_clnt,& le
n_int);n_int);
hThrd = createThread(Threadfunc,…)hThrd = createThread(Threadfunc,…) close(c);close(c); continue ; continue ; }}}}ThreadFunc() {ThreadFunc() { // child process // child process rx = fdopen(c,”r”);rx = fdopen(c,”r”); tx = fdopen(dup(c), “w”);tx = fdopen(dup(c), “w”);
// process client’s request// process client’s request …… …….... fclose(tx); fclose(rx);fclose(tx); fclose(rx); exit(0);exit(0);}}
PC
PCPCPC
Possible combination of thread and processesPossible combination of thread and processes
One process one threadOne process multiple thread
Multiple processes multipleThreads per process
Multiple processesOne thread per process
Process is still there, what’s new for Process is still there, what’s new for thread?thread?
With processWith process Virtual address space (holding process image)Virtual address space (holding process image) Protected access to CPU, files, and I/O resourcesProtected access to CPU, files, and I/O resourcesWith thread (each thread has its own..)With thread (each thread has its own..) Thread execution stateThread execution state Saved thread context (an independent PC within a Saved thread context (an independent PC within a
process)process) An execution stackAn execution stack Per-thread static storage for local variablePer-thread static storage for local variable Access to memory and resource of its process, Access to memory and resource of its process,
shared with all other threads in that processshared with all other threads in that process
Single threaded and multithreaded modelSingle threaded and multithreaded model
UserAddress
space
PCB
UserAddressspace
PCB
Userstack
Kernelstack
Userstack
Kernelstack
Userstack
Kernelstack
Userstack
Kernelstack
ThreadControlblock
ThreadControlblock
ThreadControlblock
Single-threadedprocess
MultithreadProcess model
Key benefits of multithreadingKey benefits of multithreading
Less time to create a thread than a Less time to create a thread than a processprocessLess time to terminate a thread than a Less time to terminate a thread than a processprocessLess time to switch a threadLess time to switch a threadEnhance efficiency in communication: Enhance efficiency in communication: no need for kernel to interveneno need for kernel to intervene MACH shows a factor of 10MACH shows a factor of 10
Boosted by SMPBoosted by SMP
If you install SMP motherboard and SMP If you install SMP motherboard and SMP enhanced O.S. kernel ( Windows and enhanced O.S. kernel ( Windows and Linux both support)Linux both support)Each thread can be assign to an individual Each thread can be assign to an individual CPU.CPU.The result – boosted performance The result – boosted performance
Java threadsJava threadsclass javathread extends Thread {class javathread extends Thread {int _threadindex ;int _threadindex ;int x;int x;static int threadno ; static int threadno ; // constructor// constructorjavathread(int threadindex) {javathread(int threadindex) { _threadindex = threadindex ;_threadindex = threadindex ; threadno ++ ;threadno ++ ;}}run() {run() { for (int i; i<10000; i++) for (int i; i<10000; i++) x ++ ;x ++ ; System.out.printlnSystem.out.println (“this is thread “ + _threadindex + “of” (“this is thread “ + _threadindex + “of” threadnothreadno}}
POSSIBLE OUTPUT:POSSIBLE OUTPUT:
This is main thread !This is main thread !This is thread 1 of 2This is thread 1 of 2This is thread 2 of 2This is thread 2 of 2
void main() {void main() { Thread t1 = new javathread(1);Thread t1 = new javathread(1); Thread t2 = new javathread(2);Thread t2 = new javathread(2); t1.start();t1.start(); t2.start();t2.start(); System.out.println(“This is maiSystem.out.println(“This is mai
n thread\n”);n thread\n”);}}
Like a global variable in C,
C++
javathread(int threadindex) { _threadindex = threadindex ; threadno ++ ;}
run() { for (int i; i<10000; i++) x ++ ; System.out.println (“this is thread “ + _threadindex + “of” + threadno ); }void main() { Thread t1 = new javathread(1); Thread t2 = new javathread(2); t1.start(); t2.start();}
codecodesegmentsegment
int threadno ;int threadno ;
data data segmentsegment
(0) _threadindex(0) _threadindex(4) x(4) x
(0) _threadindex(0) _threadindex(4) x(4) x
t1baset1base
t2baset2base
mov ax, [ESP+4];mov ax, [ESP+4];mov [ESI+0], eax;mov [ESI+0], eax;mov eax, threadnomov eax, threadnoinc eax ;inc eax ;mov threadno,eaxmov threadno,eax
ESIESI
heap area
Win32 Thread – an exampleWin32 Thread – an exampleint main() {int main() {
HANDLE hThrd ;HANDLE hThrd ;DWORD threadid ;DWORD threadid ;int i ;int i ;for (i=0;i<5;i++) {for (i=0;i<5;i++) { hThrd = hThrd = CreateThread(NULL,0,ThreadFunc,(LPVOID)I,0,&threadid);CreateThread(NULL,0,ThreadFunc,(LPVOID)I,0,&threadid); if (hThr) printf(“Thread launched %d\n”,i);if (hThr) printf(“Thread launched %d\n”,i);}}Sleep(2000);Sleep(2000);return EXIT_SUCCESS;return EXIT_SUCCESS;
}}DWORD WINAPI ThreadFunc(LPVOID n) {DWORD WINAPI ThreadFunc(LPVOID n) {
int i ;int i ; for (i=0;i<10;i++) {for (i=0;i<10;i++) { printf(“%d%d%d%d%d%d%d%d\n”, n,n,n,n,n,n,n,n);printf(“%d%d%d%d%d%d%d%d\n”, n,n,n,n,n,n,n,n);
}}
possible outputpossible output00000000000000Thread lauchedThread lauched1111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222Thread lauched Thread lauched
00000000000000Thread lauchedThread lauched1111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222Thread lauched Thread lauched
333333333333333333333333333333333333333333333344444443333444444444444444444444444444444444444444444444444433333333333333333333333333333333333333333333333333
Contextswitch may occurs in the middle of printf command- a type of race condition
NOTESNOTES
In multi-threading, typically you have no control In multi-threading, typically you have no control of output sequences or of output sequences or schedulingschedulingContext switching may occur in any timeContext switching may occur in any time the probility may be the probility may be 1/100000001/10000000 but consider how ma but consider how ma
ny instruction CPU may execute per secondny instruction CPU may execute per second
Your program become concurrent and Your program become concurrent and nondeternondeterministic.ministic. Same input to a concurrent program may generate difSame input to a concurrent program may generate dif
ferent outputferent output beware of the beware of the probe effectprobe effect
race conditionrace condition
AddHead(struct List *list, AddHead(struct List *list, struct Node *node){struct Node *node){ node->next = list->head ;node->next = list->head ; list->head = node;list->head = node;}}
Thread 1 Thread 2
……....AddHead(list,B)AddHead(list,B)……....
……....AddHead(list,C)AddHead(list,C)……....
race condition- race condition- if you think you are smart if you think you are smart enough, things still go wrongenough, things still go wrong
AddHead(struct List *list, AddHead(struct List *list, struct Node *node){struct Node *node){ while (flag !=0) ;while (flag !=0) ; flag = 1 ;flag = 1 ; node->next = list->head ;node->next = list->head ; list->head = node;list->head = node; flag = 0;flag = 0;}}
xor eax, eax ;xor eax, eax ;; while (flag !=0) ; while (flag !=0) L86: L86: cmp _flag, eaxcmp _flag, eax jne L86jne L86; flag = 1 ; flag = 1 mov eax, _list$[esp-4]mov eax, _list$[esp-4] mov ecx, _node$[esp-4]mov ecx, _node$[esp-4] mov _flag, 1mov _flag, 1; node->next = list->head; node->next = list->head mov edx, [eax]mov edx, [eax] mov [ecx], edxmov [ecx], edx; list->head; list->head mov [eax] , ecxmov [eax] , ecx ; flag = 0; flag = 0 mov _flag,0mov _flag,0
What is C runtime library – multi-threaded What is C runtime library – multi-threaded versionversion
Original C runtime library is not suitable for Original C runtime library is not suitable for multithreaded programmultithreaded programOriginal C runtime library uses many Original C runtime library uses many global variables and static variables -> global variables and static variables -> cause multithreads to racecause multithreads to race
NOTESNOTES
conventional C library is not made to execconventional C library is not made to execute under multithreaded programute under multithreaded programchoose the right C runtime library to linkchoose the right C runtime library to link /ML Single-threaded/ML Single-threaded /MT Multi-threaded (static)/MT Multi-threaded (static) /MD Multi-threaded DLL/MD Multi-threaded DLL /MLd Debug Single-threaded/MLd Debug Single-threaded /MTd Debug Multithreaded (static)/MTd Debug Multithreaded (static) /MDd Debug Multithreaded (DLL)/MDd Debug Multithreaded (DLL)
CloseHandleCloseHandleint main() {int main() {
HANDLE hThrd ;HANDLE hThrd ;DWORD threadid ;DWORD threadid ;int i ;int i ;for (i=0;i<5;i++) {for (i=0;i<5;i++) { hThrd = hThrd = CreateThread(NULL,0,ThreadFunc,(LPVOID)I,0,&threadiCreateThread(NULL,0,ThreadFunc,(LPVOID)I,0,&threadi
dd);); if (hThr) {if (hThr) { printf(“Thread launched %d\n”,i);printf(“Thread launched %d\n”,i); CloseHandle(hThrd)CloseHandle(hThrd)}}Sleep(2000);Sleep(2000);return EXIT_SUCCESS;return EXIT_SUCCESS;
}}
CloseHandleCloseHandle
Thread is a kernel object Thread is a kernel object A kernel object can be owned by several ownersA kernel object can be owned by several ownersEach thread when created is owned by two Each thread when created is owned by two owner- owner- the creator and the thread itselfthe creator and the thread itself. So, the . So, the reference count is two.reference count is two.When reference count is down to zeroWhen reference count is down to zero, windows , windows destroy the object.destroy the object.if a process generate many threads but do not if a process generate many threads but do not close the handle, this process may own many close the handle, this process may own many kernel thread object -> kernel thread object -> resource leaksresource leaks
Some suggestionsSome suggestions
avoid using global variables among avoid using global variables among threadsthreadsdo not share GDI objects between threaddo not share GDI objects between threadmake sure you know the status of the make sure you know the status of the threads you create, do not exit without threads you create, do not exit without waiting your threads to terminatewaiting your threads to terminatehave the main thread to handle UI (user have the main thread to handle UI (user interface)interface)
Misc Win32 functionMisc Win32 function
BOOL GetExitCodeThreadBOOL GetExitCodeThread A non-blocked system call to acquire the statuA non-blocked system call to acquire the statu
s of a threads of a threadVOID ExitThreadVOID ExitThreadDWORD WaitForSingleObjectDWORD WaitForSingleObject avoid busy waitingavoid busy waiting e.g. WaitForSingleObject(hThrd, INFINITE);e.g. WaitForSingleObject(hThrd, INFINITE);DWORD WaitForMultipleObjectsDWORD WaitForMultipleObjects same as WaitForSingleObjectsame as WaitForSingleObject
SynchronizationSynchronizationThere are few kinds multithreaded applications There are few kinds multithreaded applications which do not need synchronizations among threwhich do not need synchronizations among threads.ads.e.g., e.g., telnettelnet and and bbsbbs daemon. daemon.if your threads do not need any kind of synchroniif your threads do not need any kind of synchronization, such as telnet, you are lucky to get away zation, such as telnet, you are lucky to get away with with sync horrorsync horror..Once you need synchronization, you invite concOnce you need synchronization, you invite concurrency errors to your program.urrency errors to your program. deadlockdeadlock race conditionsrace conditions starvationstarvation
Concurrency errorsConcurrency errorsare known to be are known to be
hard to detect (irreproducible)hard to detect (irreproducible) hard to debug (probe effect)hard to debug (probe effect) hard to get a correct fixhard to get a correct fix
Currently, there is no effective way to detect, debugCurrently, there is no effective way to detect, debugYour better choice is Your better choice is
be careful at the beginning (spend more time in design stage)be careful at the beginning (spend more time in design stage) use the simplest synchronization structure that cannot be wrong use the simplest synchronization structure that cannot be wrong
or proved to be corrector proved to be correct do not use complicated synchronization structure unless you are do not use complicated synchronization structure unless you are
sure what you are doingsure what you are doing sacrifices some performance in exchange of correctnesssacrifices some performance in exchange of correctness..
Synchronization mechanism in Synchronization mechanism in Win32Win32
Critical sectionsCritical sectionsMutexesMutexesSemaphoreSemaphore
Critical SectionsCritical Sections
VOID InitializeCriticalSectionVOID InitializeCriticalSectionVOID DeleteCriticalSectionVOID DeleteCriticalSectionVOID EnterCriticalSectionVOID EnterCriticalSectionVOID LeaveCriticalSectionVOID LeaveCriticalSection
AddHead(struct List *plist, AddHead(struct List *plist, struct Node *node){struct Node *node){ EnterCriticalSection(&plist->critical_sec);EnterCriticalSection(&plist->critical_sec); node->next = list->head ;node->next = list->head ; list->head = node;list->head = node; LeaveCriticalSection(&plist->critical_sec):LeaveCriticalSection(&plist->critical_sec):}}
typedef struct _Node {typedef struct _Node { struct _Node *next ;struct _Node *next ; int data ;int data ;} Node ;} Node ;typedef struct _List { typedef struct _List { Node *head ;Node *head ; CRITICAL_SECTION critical_sec ;CRITICAL_SECTION critical_sec ;} List ;} List ;
List *CreateList() {List *CreateList() { List *plist = malloc(sizeof(pList));List *plist = malloc(sizeof(pList)); pList-> head = NULL ;pList-> head = NULL ; InitializeCriticalSection(&pList->critical_sec);InitializeCriticalSection(&pList->critical_sec); return pList ;return pList ;}}
AddHead(struct List *plist, AddHead(struct List *plist, struct Node *node){struct Node *node){ EnterCriticalSection(&plist->critical_sec);EnterCriticalSection(&plist->critical_sec); node->next = list->head ;node->next = list->head ; list->head = node;list->head = node; LeaveCriticalSection(&plist->critical_sec):LeaveCriticalSection(&plist->critical_sec):}}
Thread 1
…..AddHead(list,A)……
Thread 2
……AddHead(list,B)……
ContinuedContinued
There is at most one thread can There is at most one thread can manipulate the linked listmanipulate the linked listdo not use do not use sleep()sleep() or or Wait..()Wait..() in a critical in a critical section -> cause deadlocksection -> cause deadlockif a thread enter a critical section and exit, if a thread enter a critical section and exit, the critical section is locked by Window NTthe critical section is locked by Window NT
DeadlockDeadlockvoid SwapLists(List *list1, List *list2) {void SwapLists(List *list1, List *list2) { List *tmp_list ;List *tmp_list ; EnterCriticalSection(list1-> critical_sec);EnterCriticalSection(list1-> critical_sec); EnterCriticalSection(list2->critical_sec);EnterCriticalSection(list2->critical_sec); tmp_list = list1->headtmp_list = list1->head list1->head = list2->headlist1->head = list2->head list2->head = tmp_list ;list2->head = tmp_list ; LeaveCriticalSection(list1->critical_sec);LeaveCriticalSection(list1->critical_sec); LeaveCriticalSection(list2->critical_sec);LeaveCriticalSection(list2->critical_sec);}}
• Holding a resouce and then request another resource -> possible deadlock
void SwapLists(List *list1, List *list2) {void SwapLists(List *list1, List *list2) { List *tmp_list ;List *tmp_list ; EnterCriticalSection(list1-> critical_sec);EnterCriticalSection(list1-> critical_sec); EnterCriticalSection(list2->critical_sec);EnterCriticalSection(list2->critical_sec); tmp_list = list1->headtmp_list = list1->head list1->head = list2->headlist1->head = list2->head list2->head = tmp_list ;list2->head = tmp_list ; LeaveCriticalSection(list1->critical_sec);LeaveCriticalSection(list1->critical_sec); LeaveCriticalSection(list2->critical_sec);LeaveCriticalSection(list2->critical_sec);}}
Thread 1
……
Swap_lists…………
Thread 2…………Swap_lists…….…….
Mutex (MUTual EXclusion)Mutex (MUTual EXclusion)
Similar to critical sectionSimilar to critical sectioncause 100 times of time to lock a process/tcause 100 times of time to lock a process/threadhread CS is executed in user mode (only within a prCS is executed in user mode (only within a pr
ocess)ocess) mutex is executed in kernel mode , it can crosmutex is executed in kernel mode , it can cros
s process (interprocess communication)s process (interprocess communication)
Comparision of CS/MutexComparision of CS/Mutex
CreateMutexCreateMutexOpenMutexOpenMutex
WaitForSingleObject()WaitForSingleObject()WaitForMultipleObject()WaitForMultipleObject()MsgWaitForMultipleObjectMsgWaitForMultipleObject
ReleaseMutexReleaseMutex
CloseHandleCloseHandle
VOID InitializeCriticalSectionVOID InitializeCriticalSection
VOID EnterCriticalSectionVOID EnterCriticalSection
VOID LeaveCriticalSectionVOID LeaveCriticalSection
VOID DeleteCriticalSectionVOID DeleteCriticalSection
typedef struct _Node {typedef struct _Node { struct _Node *next ;struct _Node *next ; int data ;int data ;} Node ;} Node ;typedef struct _List { typedef struct _List { Node *head ;Node *head ; HANDLE hMutex ;HANDLE hMutex ;} List ;} List ;
List *CreateList() {List *CreateList() { List *plist = malloc(sizeof(pList));List *plist = malloc(sizeof(pList)); pList-> head = NULL ;pList-> head = NULL ; plist->hMutex = CreateMutex(NULL,false,NULL)plist->hMutex = CreateMutex(NULL,false,NULL) return pList ;return pList ;}}
void SwapLists(List *list1, List *list2) {void SwapLists(List *list1, List *list2) { List *tmp_list ;List *tmp_list ; HANDLE arrhandles[2] ;HANDLE arrhandles[2] ; arrhandles[0] = list1-> hMutex ;arrhandles[0] = list1-> hMutex ; arrhandles[1] = list2-> hMutex ;arrhandles[1] = list2-> hMutex ; WaitForMultipleObjects(2, arrhandles, TRUE, INFINITE);WaitForMultipleObjects(2, arrhandles, TRUE, INFINITE); tmp_list = list1->headtmp_list = list1->head list1->head = list2->headlist1->head = list2->head list2->head = tmp_list ;list2->head = tmp_list ; ReleaseMutex(arrhandles[0]);ReleaseMutex(arrhandles[0]); ReleaseMutex(arrhandles[1]);ReleaseMutex(arrhandles[1]);}}
NOTESNOTES
When a When a mutexmutex is created, no thread/proce is created, no thread/process have a lock on it, ss have a lock on it, it is ready to triggerit is ready to trigger So, a call to Wait..() will immediately return, otSo, a call to Wait..() will immediately return, ot
herwise a call to Wait…() will be blocked.herwise a call to Wait…() will be blocked.
mutex is exactly the same as a semaphore mutex is exactly the same as a semaphore with semaphore value 1.with semaphore value 1.
SemaphoreSemaphore
Synchronization tool (provided by the OS) that do not require busy waiting
A semaphore S is an integer variable that, apart from initialization, can only be accessed through 2 atomic and mutually exclusive operations:– P(S), down(S), wait(S)– V(S), up(S), signal(S)
To avoid busy waiting: when a process has to wait, it will be put in a blocked queue of processes waiting for the same event
Semaphores in Win32Semaphores in Win32
HANDLE CreateSemaphoreHANDLE CreateSemaphorevoid WaitForSingleObject ( like P())void WaitForSingleObject ( like P())BOOL ReleaseSemaphore (like V())BOOL ReleaseSemaphore (like V())
They are the same as the semaphore taugThey are the same as the semaphore taught in O.S.ht in O.S.use Wait…() to decrease a semaphore or use Wait…() to decrease a semaphore or block a thread when its value is zero.block a thread when its value is zero.
Semaphore implementationSemaphore implementationP(S): S.count--; if (S.count<0) { block this process place this process in S.queue }
V(S): S.count++; if (S.count<=0) { remove a process P from S.queue place this process P on ready list }
S.count must be initialized to a nonnegative value (depending on application)
Using semaphores for solving critical section problems
For n processesInitialize S.count to 1Then only 1 process is allowed into CS (mutual exclusion)To allow k processes into CS, we initialize S.count to k
Process Pi:repeat P(S); CS V(S); RSforever
Problems with semaphores
semaphores provide a powerful tool for enforcing mutual exclusion and coordinate processesBut P(S) and V(S) are scattered among several processes. Hence, difficult to understand their effectsUsage must be correct in all the processesOne bad (or malicious) process can fail the entire collection of processes
IMPORTANT:IMPORTANT:Suggestion and TrenSuggestion and Trendd
The current trend of synchronization is called The current trend of synchronization is called sysynchronized shared objectsnchronized shared objectsDo not use semaphore in thread’s main programDo not use semaphore in thread’s main program/function, it is difficult to debug/function, it is difficult to debuggather all the semaphore, mutex, critical sectiongather all the semaphore, mutex, critical sections in an shared object’s methodss in an shared object’s methodsThread’s main function need not worry about the Thread’s main function need not worry about the synchronizationsynchronizationLet the shared object implementer (usually an exLet the shared object implementer (usually an experienced personel in concureent programming) perienced personel in concureent programming) worry about the synchronizationworry about the synchronization
Synchronization via a shared object Synchronization via a shared object in Java in Java
class PRODUCER class PRODUCER extends Thread {extends Thread {buffer b ; // the shared objectbuffer b ; // the shared objectPRODUCER(buffer _b) PRODUCER(buffer _b) { b = _b ; }{ b = _b ; }run() {run() { do {do { data = generate_a_data();data = generate_a_data(); b.append(data);b.append(data); } while (1);} while (1);} }
class CONSUMER class CONSUMER extends Thread {extends Thread {buffer b ; // the shared objectbuffer b ; // the shared objectCONSUMER(buffer _b) CONSUMER(buffer _b) { b = _b ; }{ b = _b ; }run() {run() { do {do { b.take(data);b.take(data); output data ;output data ; } while (1);} while (1);} }
main() {main() { buffer rb = new buffer() ;buffer rb = new buffer() ; Thread p = new PRODUCER(rb);Thread p = new PRODUCER(rb); Thread c = new CONSUMER(rb);Thread c = new CONSUMER(rb); p.start();p.start(); c.start();c.start();
class buffer {class buffer {??}}
Let’s do it with handLet’s do it with hand