Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
Lecture14:MutualExclusion,LocksandBarrierwithPThreads
ConcurrentandMul=coreProgramming
DepartmentofComputerScienceandEngineeringYonghongYan
[email protected]/~yan
1
ReviewandOverview
• ThreadbasicsandthePOSIXThreadAPI– Processvsthreads
• ThreadcreaHon,terminaHonandjoining– pthread_create,pthread_joinandpthread_exit– BoxingmulHpleargumentsinstructtopasstothreadfuncHon
• Threadsafety• Synchroniza=onprimi=vesinPthreads
– Mutualexclusion,locksandbarrier
2
DataRacinginaMul=threadProgramConsider:/* each thread to update shared variable best_cost */ !
!if (my_cost < best_cost) !
best_cost = my_cost;
– twothreads,– theiniHalvalueofbest_costis100,– thevaluesofmy_costare50and75forthreadst1andt2!!
best_cost = my_cost;• Thevalueofbest_costcouldbe50or75!• Thevalue75doesnotcorrespondtoanyserializaHonofthetwo
threads.
3
T1 T2
if (my_cost (50) < best_cost)! !
best_cost = my_cost;
if (my_cost (75) < best_cost)!!
best_cost = my_cost;
SameSitua=onforReading/Upda=ngaSingleVariable
intcount=0;int*cp=&count;….*cp++;/*bytwothreads*/
4Picturesfromwikipedia:h[p://en.wikipedia.org/wiki/Race_condiHon
Whythishappens
Read/writetothesameloca=onbythetwothreadsinterleaved
5
GeneralSolu=on:Cri=calSec=onandMutualExclusion
• CriHcalsecHon=asegmentthatmustbeexecutedbyonlyonethreadatanyHme ! !!
• MutexlocksprotectcriHcalsecHonsinPthreads– lockedandunlocked– AtanypointofHme,onlyonethreadcanacquireamutexlock
• Usingmutexlocks– requestlockbeforeexecuHngcriHcalsecHon– entercriHcalsecHonwhenlockgranted– releaselockwhenleavingcriHcalsecHon
if (my_cost < best_cost)! best_cost = my_cost;
6
MutualExclusionusingPthreadMutexint pthread_mutex_lock (pthread_mutex_t *mutex_lock); !int pthread_mutex_unlock (pthread_mutex_t *mutex_lock); !int pthread_mutex_init (pthread_mutex_t !*mutex_lock,! const pthread_mutexattr_t *lock_attr);!
pthread_mutex_tcost_lock;intmain(){...pthread_mutex_init(&cost_lock,NULL);pthread_create(&thhandle,NULL,find_best,…)...}void*find_best(void*list_ptr){...pthread_mutex_lock(&cost_lock);//enterCSif(my_cost<best_cost)best_cost=my_cost;pthread_mutex_unlock(&cost_lock);//leaveCS}
Cri=calSec=on
pthread_mutex_lockblocksthecallingthreadifanotherthreadholdsthelockWhenpthread_mutex_lockcallreturns1. Mutexislocked,enterCS2. Anyotherlockinga[empt(callto
thread_mutex_lock)willcausetheblockingofthecallingthread
Whenpthread_mutex_unlockreturns1. Mutexisunlocked,leaveCS2. Onethreadwhoblockson
thread_mutex_lockcallwillacquirethelockandenterCS
7
Producer-ConsumerUsingLocksConstrains:• Theproducerthreads
– mustnotoverwritethesharedbufferwhentheprevioustaskhasnotbeenpickedupbyaconsumerthread.
• Theconsumerthreads– mustnotpickuptasksunHlthereissomethingpresentinthe
shareddatastructure.– IndividualconsumerthreadshouldpickuptasksoneataHme
Conten=on:– Betweenproducers– Betweenconsumers– Betweenproducersandconsumers
8
Producer-ConsumerUsingLockspthread_mutex_t task_queue_lock; int task_available; main() {
.... task_available = 0; pthread_mutex_init(&task_queue_lock, NULL); ....
}
9
void *producer(void *producer_thread_data) { .... while (!done()) { inserted = 0; create_task(&my_task); while (inserted == 0) { pthread_mutex_lock(&task_queue_lock); if (task_available == 0) { insert_into_queue(my_task); task_available = 1; inserted = 1; } pthread_mutex_unlock(&task_queue_lock); } } }
void *consumer(void *consumer_thread_data) { int extracted; struct task my_task; while (!done()) { extracted = 0; while (extracted == 0) { pthread_mutex_lock(&task_queue_lock); if (task_available == 1) { extract_from_queue(&my_task); task_available = 0; extracted = 1; } pthread_mutex_unlock(&task_queue_lock); } process_task(my_task); } }
Cri=calSec=on
Notethepurposeofinsertedandextracedvariables
ThreeTypesofMutexes
• Normal– Deadlocksifathreadalreadyhasalockandtriesasecondlockonit.
• Recursive– AllowsasinglethreadtolockamutexasmanyHmesasitwants.
• Itsimplyincrementsacountonthenumberoflocks.– Alockisrelinquishedbyathreadwhenthecountbecomeszero.
• Errorcheck– Reportsanerrorwhenathreadwithalocktriestolockitagain(as
opposedtodeadlockinginthefirstcase,orgranHngthelock,asinthesecondcase).
• Thetypeofthemutexcanbesetinthea[ributesobjectbeforeitispassedatHmeofiniHalizaHon– pthread_mutex_a[r_init
10
OverheadsofLocking
11
• LocksenforceserializaHon– ThreadmustexecutecriHcalsecHonsoneameranother
• LargecriHcalsecHonscanleadtosignificantperformancedegradaHon.
• Reducetheblockingoverheadassociatedwithlocksusing:
int pthread_mutex_trylock ( pthread_mutex_t *mutex_lock);
– acquirelockifavailable– returnEBUSYifnotavailable– enablesathreadtodosomethingelseiflockunavailable
• pthreadtrylocktypicallymuchfasterthanlockoncertainsystems
– ItdoesnothavetodealwithqueuesassociatedwithlocksformulHplethreadswaiHngonthelock.
12
Condi=onVariablesforSynchroniza=on
Acondi=onvariable:associatedwithapredicateandamutex– AsyncvariableforacondiHon,e.g.mybalance>500
• AthreadcanblockitselfunHlacondiHonbecomestrue
– Whenblocked,releasemutexsootherscanacquireit• WhenacondiHonbecomestrue,observedbyanotherthread,thecondiHonvariableisusedtosignalotherthreadswhoareblocked
• AcondiHonvariablealwayshasamutexassociatedwithit.– AthreadlocksthismutexandteststhecondiHon
13
Condi=onVariablesforSynchroniza=on/*theopaquedatastructure*/pthread_cond_t!/*ini=aliza=onanddestroying*/int pthread_cond_init(pthread_cond_t *cond, ! const pthread_condattr_t *attr); !
int pthread_cond_destroy(pthread_cond_t *cond); !!/*blockandreleaselockun=lacondi=onistrue*/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 *wtime);! !/*signaloneorallwai=ngthreadsthatcondi=onistrue*/int pthread_cond_signal(pthread_cond_t *cond); !int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_cond_t cond_queue_empty, cond_queue_full; !pthread_mutex_t task_queue_cond_lock; !int task_available; !/* other data structures here */ !!main() { !/* declarations and initializations */ !task_available = 0; !pthread_cond_init(&cond_queue_empty, NULL); !pthread_cond_init(&cond_queue_full, NULL); !pthread_mutex_init(&task_queue_cond_lock, NULL); !/* create and join producer and consumer threads */ !
} !
14
Producer-ConsumerUsingCondi=onVariables
• TwocondiHons:• Queueisfull:(task_available==1)ßcond_queue_full• Queueisempty:(task_available==0)ßcond_queue_empty
• AmutexforprotecHngaccessingthequeue(CS):task_queue_cond_lock
void *producer(void *producer_thread_data) { !int inserted; !while (!done()) { !
create_task(); !pthread_mutex_lock(&task_queue_cond_lock);! !while (task_available == 1) !pthread_cond_wait(&cond_queue_empty,! &task_queue_cond_lock);! !
insert_into_queue(); !task_available = 1; CS!!pthread_cond_signal(&cond_queue_full);! !pthread_mutex_unlock(&task_queue_cond_lock); !
} !} !
15
Producer-ConsumerUsingCondi=onVariables
Releasemutex(unlock)whenblocked/wait
Acquiremutex(lock)whenawaken
Producer:1. Waitforqueuetobecomeempty,no=fiedbyconsumerthroughcond_queue_empty2. insertintoqueue3. Signalconsumerthroughcond_queue_full
1
2
3
void *consumer(void *consumer_thread_data) { !while (!done()) { !pthread_mutex_lock(&task_queue_cond_lock);! !while (task_available == 0) !
pthread_cond_wait(&cond_queue_full, !&task_queue_cond_lock); !!
my_task = extract_from_queue(); !task_available = 0; !!pthread_cond_signal(&cond_queue_empty);! !pthread_mutex_unlock(&task_queue_cond_lock); !process_task(my_task); !
} !} !
16
Consumer:1. Waitforqueuetobecomefull,no=fiedbyproducerthroughcond_queue_full2. Extracttaskfromqueue3. Signalproducerthroughcond_queue_empty
Releasemutex(unlock)whenblocked/wait
Acquiremutex(lock)whenawaken
Producer-ConsumerUsingCondi=onVariables
1
2
3
ThreadandSynchroniza=onA^ributes
• Threemajorobjects– pthread_t– pthread_mutex_t– pthread_cond_t
• Defaulta[ributeswhenbeingcreated/iniHalized– NULL
• Ana[ributesobjectisadata-structurethatdescribesenHty(thread,mutex,condiHonvariable)properHes.– OncetheseproperHesareset,thea[ributesobjectcanbe
passedtothemethodiniHalizingtheenHty.– Enhancesmodularity,readability,andeaseofmodificaHon.
17
A^ributesObjectsforThreads
18
• IniHalizeana[ributeobjectsusingpthread_attr_init!
• IndividualproperHesassociatedwiththea[ributesobjectcanbechangedusingthefollowingfuncHons:pthread_attr_setdetachstate, !pthread_attr_setguardsize_np, !pthread_attr_setstacksize, !pthread_attr_setinheritsched,!pthread_attr_setschedpolicy, and!pthread_attr_setschedparam !
A^ributesObjectsforMutexes
19
• IniHalizeana[ributesobjectusingfuncHon:pthread_mutexattr_init.
• pthread_mutexa^r_se^ype_npforseqngthemutextypepthread_mutexa^r_se^ype_np(pthread_mutexa^r_t*a^r,inttype); !
• Specifictypes:– PTHREAD_MUTEX_NORMAL_NP– PTHREAD_MUTEX_RECURSIVE_NP– PTHREAD_MUTEX_ERRORCHECK_NP
A^ributesObjectsforCondi=onVariable
• IniHalizeana[ributeobjectusingpthread_condattr_init
• int pthread_conda^r_setpshared(pthread_conda^r_t*ca^r,intpshared)tospecifiesthescopeofacondiHonvariabletoeitherprocessprivate(intraprocess)orsystemwide(interprocess)viapshared– PTHREAD_PROCESS_SHARED– PTHREAD_PROCESS_PRIVATE
20
• PthreadMutexandCondi=onVariablesaretwobasicsyncoperaHons.
• Higherlevelconstructscanbebuiltusingbasicconstructs.– Read-writelocks– Barriers
• PthreadhasitscorrespondingimplementaHon– pthread_rwlock_t– pthread_barrier_t
• WewilldiscussourownimplementaHons
21
CompositeSynchroniza=onConstructs
22
Read-WriteLocks
• Concurrentaccesstodatastructure:– Readfrequentlybut– Wri[eninfrequently
• Behavior:– Concurrentread:Areadrequestisgrantedwhenthereare
otherreadsornowrite(pendingwriterequest).– Exclusivewrite:Awriterequestisgrantedonlyifthereisno
writeorpendingwriterequest,orreads.• Interfaces:
– Therwlockdatastructure:structmylib_rwlock_t– Readlock:mylib_rwlock_rlock– writelock:mylib_rwlock_wlock– Unlock:mylib_rwlock_unlock.
• Twotypesofmutualexclusions– 0/1mutexforprotecHngaccesstowrite– Countermutex(semaphore)forcounHngreadaccess
• Componentsketch– acountofthenumberofreaders,– 0/1integerspecifyingwhetherawriterispresent,– acondiHonvariablereaders_proceedthatissignaledwhenreaders
canproceed,– acondiHonvariablewriter_proceedthatissignaledwhenoneofthe
writerscanproceed,– acountpending_writersofpendingwriters,and– apthread_mutex_tread_write_lockassociatedwiththeshareddata
structure
23
Read-WriteLocks
24
Read-WriteLocks
typedef struct { !int readers; !int writer; !pthread_cond_t readers_proceed; !pthread_cond_t writer_proceed; !int pending_writers; !pthread_mutex_t read_write_lock; !
} mylib_rwlock_t; !!void mylib_rwlock_init (mylib_rwlock_t *l) { !l->readers=0; l->writer=0; l->pending_writers=0; !pthread_mutex_init(&(l->read_write_lock), NULL); !pthread_cond_init(&(l->readers_proceed), NULL); !pthread_cond_init(&(l->writer_proceed), NULL); !
} !
Read-WriteLocks
void mylib_rwlock_rlock(mylib_rwlock_t *l) { !pthread_mutex_lock(&(l->read_write_lock)); !!while ((l->pending_writers > 0) || (l->writer > 0)) !
pthread_cond_wait(&(l->readers_proceed), !&(l->read_write_lock)); !!
l->readers ++; !!pthread_mutex_unlock(&(l->read_write_lock)); !
} !
25
Readerlock:1. ifthereisawriteorpendingwriters,performcondi=onwait,2. elseincrementcountofreadersandgrantreadlock
1
2
Read-WriteLocksvoid mylib_rwlock_wlock(mylib_rwlock_t *l) { !pthread_mutex_lock(&(1->read_write_lock)); !1->pending_writers ++; !!while ((1->writer > 0) || (1->readers > 0)) { !
pthread_cond_wait(&(1->writer_proceed), ! &(1->read_write_lock));!
} !!
1->pending_writers --; !1->writer ++; !!pthread_mutex_unlock(&(1->read_write_lock)); !
} !
26
Writerlock:1. Iftherearereadersorwriters,incrementpendingwriters
countandwait.2. Onbeingwoken,decrementpendingwriterscountand
incrementwritercount
1
2
Read-WriteLocks
void mylib_rwlock_unlock(mylib_rwlock_t *l) { ! pthread_mutex_lock(&(1->read_write_lock)); ! if (1->writer > 0) /* only writer */! 1->writer = 0; !
else if (1->readers > 0) /* only reader */! 1->readers --; !
pthread_mutex_unlock(&(1->read_write_lock)); !! if ((1->readers == 0) && (1->pending_writers > 0)) ! pthread_cond_signal(&(1->writer_proceed)); !
else if (1->readers > 0) ! pthread_cond_broadcast(&(1->readers_proceed)); !
} !
27
Reader/Writerunlock:1. Ifthereisawritelockthenunlock2. Iftherearereadlocks,decrementcountofreadlocks.3. Ifthereadcountbecomes0andthereisapendingwriter,no=fywriter4. Otherwiseiftherearependingreaders,letthemallgothrough
1
2
3
4
Barrier
• AbarrierholdsoneormulHplethreadsunHlallthreadsparHcipaHnginthebarrierhavereachedthebarrierpoint
28
Barrier
• Needsacounter,amutexandacondi=onvariable– Thecounterkeepstrackofthenumberofthreadsthathave
reachedthebarrier.• Ifthecountislessthanthetotalnumberofthreads,thethreadsexecuteacondiHonwait.
– Thelastthreadentering(master)wakesupallthethreadsusingacondiHonbroadcast.
29
typedef struct {! int count;!pthread_mutex_t count_lock;!pthread_cond_t ok_to_proceed;!
} mylib_barrier_t;!!void mylib_barrier_init(mylib_barrier_t *b) {!b->count = 0;!pthread_mutex_init(&(b->count_lock), NULL);!pthread_cond_init(&(b->ok_to_proceed), NULL);!
}!
Barriers
void mylib_barrier (mylib_barrier_t *b, int num_threads) {!pthread_mutex_lock(&(b->count_lock));!!b->count ++;!if (b->count == num_threads) {!
b->count = 0;!pthread_cond_broadcast(&(b->ok_to_proceed));!
} else!while (pthread_cond_wait(&(b->ok_to_proceed),!&(b->count_lock)) != 0);!!
pthread_mutex_unlock(&(b->count_lock));!}!
30
Barrier1. Eachthreadincrementsthecounterandcheckwhetherallreach2. Thethread(master)whodetectthatallreachessignalotherstoproceed3. Ifnotallreach,thethreadwaits
1
2
3
Flat/LinearvsTree/LogBarrier
31
• Linear/Flatbarrier.– O(n)fornthread– AsinglemastertocollectinformaHonofallthreadsandnoHfythemto
conHnue• Tree/Logbarrier
– Organizethreadsinatreelogically– MulHplesubmastertocollectandnoHfy– RunHmegrowsasO(logp).
Barrier
• ExecuHonHmeof1000sequenHalandlogarithmicbarriersasafuncHonofnumberofthreadsona32processorSGIOrigin2000.
32
References
• Adaptedfromslides“ProgrammingSharedAddressSpacePlaxorms”byAnanthGrama.BradfordNichols,DickBu[lar,JacquelineProulxFarrell.
• “PthreadsProgramming:APOSIXStandardforBe[erMulHprocessing.”O'ReillyMedia,1996.
• Chapter7.“IntroducHontoParallelCompuHng”byAnanthGrama,AnshulGupta,GeorgeKarypis,andVipinKumar.AddisonWesley,2003
• Otherpthreadtopics– intpthread_key_create(pthread_key_t*key,void(*destroy)(void*))– intpthread_setspecific(pthread_key_tkey,constvoid*value)– void*pthread_getspecific(pthread_key_tkey)
33
Allevia=ngLockingOverhead(Example)/* Finding k matches in a list */ !void *find_entries(void *start_pointer) { !/* This is the thread function */ !struct database_record *next_record; !int count; !current_pointer = start_pointer; !do { !
next_record = find_next_entry(current_pointer); !count = output_record(next_record); !
} while (count < requested_number_of_records); !} !int output_record(struct database_record *record_ptr) { !int count; !pthread_mutex_lock(&output_count_lock); !output_count ++; !count = output_count; !pthread_mutex_unlock(&output_count_lock); !if (count <= requested_number_of_records) !
print_record(record_ptr); !return (count); !
} ! 34
Allevia=ngLockingOverhead(Example)/* rewritten output_record function */ !int output_record(struct database_record
*record_ptr) { !int count; !int lock_status; !lock_status=pthread_mutex_trylock(&output_count_lock); !if (lock_status == EBUSY) { !
insert_into_local_list(record_ptr); !return(0); !
} else { !count = output_count; !output_count += number_on_local_list + 1; !pthread_mutex_unlock(&output_count_lock); !print_records(record_ptr, local_list, !
requested_number_of_records - count); !return(count + number_on_local_list + 1); !
} !} !
35