Sysprog 14
-
Upload
ahmed-mekkawy -
Category
Technology
-
view
1.874 -
download
0
Transcript of Sysprog 14
C/C++ Linux System Programming
Session 14
User-space System Programming
session 4
Outline
Threads: Concepts and Linux Implementation
Creation and Termination
Cancellation
Mutual Exclusion and Threads
Process vs. Threads
Threads
A lightweight process:
Share address space (unlike process)
Another execution context (like a process)
Why?
IPC
Dedicated (blocking) listener: Consider IPC or Device case
Linux Implementation of Threads
Clone system call:
Part of a thread group (2.6):
all have same TGID (PID)
Have separate TID (gettid)
Same signal dispositions (separate masks)
Any thread can wait for the child of any other thread
A common VM
Ability to pass start of exec stack
Scheduled and context-switched as processes
Rest is in User-space (libpthread.so)
Pthread Object Template:
pthread_xxx_t
int pthread_xxx_init (pthread_xxx_t *obj, pthread_xxxattr_t *attr);
int pthread_xxx_destroy (pthread_xxx_t *obj);
Attribute Objects Template:
Initialization/Deletion of type xxx:
int pthread_xxxattr_destroy(pthread_xxxattr_t *attr);
int pthread_xxxattr_init(pthread_xxxattr_t *attr);
get/set attribute type xxx, attribute aaa:
int pthread_xxxattr_getaaa(pthread_xxxattr_t *attr, int *val);
int pthread_xxxattr_setaaa(pthread_xxxattr_t *attr, int val);
Thread creation / termination
int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);
void pthread_exit(void *value_ptr);
Thread attributes (pthread_attr_t)
pthread_t opaque identifier:
pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);
Reaping
Wait equivalent (from any thread not just creator):
int pthread_join(pthread_t thread, void **value_ptr);
To dodge reaping:
int pthread_detach(pthread_t thread);
PTHREAD_CREATE_DETACHED:
No need to reap (reaping would fail)
Thread Specific Data
Need some memory to appear differently to different threads
Memory is keyed, key created/deleted once:
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*)); // before any thread uses it
int pthread_key_delete(pthread_key_t key); // after all threads are done with it
Destructor is thread specific
To retrieve/modify memory:
void *pthread_getspecific(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value);
Cancelling Threads
int pthread_cancel(pthread_t thread);
Asynchronous
not a signal
Cleanup handling only (unlike signals)
Order:
Cancel call
Cancellation point
Cleanup handlers
Thread-specific data destructors
Cancellability:
For critical sections, can't cancel
int pthread_setcancelstate(int state, int *oldstate); // PTHREAD_CANCEL_ENABLE/DISABLE
For control over cancel-safe points
int pthread_setcanceltype(int type, int *oldtype); // PTHREAD_CANCEL_ASYNCHRONOUS/DEFERRED
To place a cancellation point:
void pthread_testcancel(void);
Push/pop mindset, call sets on module entry, and restore on module exit
Cleanup Stack
void pthread_cleanup_pop(int execute);
void pthread_cleanup_push(void (*routine)(void*), void *arg);
Execution upon:
Exit
Cancel
Pop with non-zero execute
Both in same lexical scope
static RETSIGTYPE sigexit_handler(int signum){ int i; nslcd_exitsignal=signum; /* cancel all running threads */ for (i=0;ildc_threads;i++) if (pthread_cancel(nslcd_threads[i])) { }}
static void worker_cleanup(void *arg){ MYLDAP_SESSION *session=(MYLDAP_SESSION *)arg; myldap_session_close(session);}
static void *worker(void UNUSED(*arg)){ MYLDAP_SESSION *session; /* create a new LDAP session */ session=myldap_create_session(); /* clean up the session if we're done */ pthread_cleanup_push(worker_cleanup,session); /* start waiting for incoming connections */ while (1) { /* wait for a new connection */ acceptconnection(session); } pthread_cleanup_pop(1); return NULL;}
int main(int argc,char *argv[]){ ... install_sighandler(SIGTERM,sigexit_handler); install_sighandler(SIGUSR1,sigexit_handler); install_sighandler(SIGUSR2,sigexit_handler); nslcd_threads= (pthread_t *)malloc(nslcd_cfg->ldc_threads*sizeof(pthread_t)); for (i=0;ildc_threads;i++) { if (pthread_create(&nslcd_threads[i],NULL,worker,NULL)) { ... exit(EXIT_FAILURE); } } for (i=0;ildc_threads;i++) { if (pthread_join(nslcd_threads[i],NULL)) {... exit(EXIT_FAILURE); } }}
Mutual Exclusion
Threads are much more prone to race conditions why?
pthread_mutex_t
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_t is strictly for mutual exclusion, not synchronization (unlike...?)
Mutex Object: pthread_mutex
Initialization:
Static:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
Non-static:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
Mutex Types
Type Attribute Values
PTHREAD_MUTEX_DEFAULT: deadlock on double lock by same thread (fast)
PTHREAD_MUTEX_RECURSIVE: no deadlock, but same # of unlocks before release
PTHREAD_MUTEX_ERRORCHECK: error on double lock by same thread
RT Attributes:
Protocol:
PTHREAD_PRIO_NONE
PTHREAD_PRIO_INHERIT: If a higher priority thread is blocked on this, execute at that its prio
PTHREAD_PRIO_PROTECT: Execute at max (mine, ceiling {all my other mutexes})
Prioceiling:
Highest possible priority to run at: should be > highest priority that locks this mutex
Futex
An area in memory used for mutexing threads, atomic operations
Futex system call in contended cases
By mmapping this (MMAP_SHARED), we have full kernel support, thus
Sharing Attribute
Another Mutex Object: Read/Write Locks
Multiple concurrent readers
only one writer allowed (Lock state)
Attributes: sharing
Read:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
Write:
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
Unlock:
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
Condition Variables
Synchronization
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Attributes: sharing
Always mutexed (why?)
Implicit cancellation point upon cancel, do not consume
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t mutex);
Atomically: release mutex and wait on condition, acquired on wakeup
int pthread_cond_broadcast(pthread_cond_t *cond); // all
Int pthread_cond_signal(pthread_cond_t *cond); // at least one
static voidPushMessage (WMMsgQueuePtr pQueue, WMMsgNodePtr pNode){ /* Lock the queue mutex */ pthread_mutex_lock (&pQueue->pmMutex);
pNode->pNext = NULL; if (pQueue->pTail != NULL) { pQueue->pTail->pNext = pNode; } pQueue->pTail = pNode; if (pQueue->pHead == NULL) { pQueue->pHead = pNode; }
/* Increase the count of elements in the queue by one */ ++g_nQueueSize;
/* Release the queue mutex */ pthread_mutex_unlock (&pQueue->pmMutex);
/* Signal that the queue is not empty */ pthread_cond_signal (&pQueue->pcNotEmpty);}
static WMMsgNodePtrPopMessage (WMMsgQueuePtr pQueue, WMInfoPtr pWMInfo){ /* Lock the queue mutex */ pthread_mutex_lock (&pQueue->pmMutex);
/* Wait for --- */ while (pQueue->pHead == NULL) { pthread_cond_wait (&pQueue->pcNotEmpty, &pQueue->pmMutex); }
pNode = pQueue->pHead; if (pQueue->pHead != NULL) { pQueue->pHead = pQueue->pHead->pNext; }
if (pQueue->pTail == pNode) { pQueue->pTail = NULL; }
/* Drop the number of elements in the queue by one */ --g_nQueueSize;
/* Release the queue mutex */ pthread_mutex_unlock (&pQueue->pmMutex);
return pNode;}
Process vs Thread
Ease of communication
Creation overhead
Potential for race conditions
Vulnerability coupling
SMP systems
Click to edit the title text
Click to edit the outline text format
Second Outline Level
Third Outline Level
Fourth Outline Level
Fifth Outline Level
Sixth Outline Level
Seventh Outline Level
Eighth Outline Level
Ninth Outline Level
Muokkaa otsikon tekstimuotoa napsauttamalla
Muokkaa jsennyksen tekstimuotoa napsauttamalla
Toinen jsennystaso
Kolmas jsennystaso
Neljs jsennystaso
Viides jsennystaso
Kuudes jsennystaso
Seitsems jsennystaso
Kahdeksas jsennystaso
Yhdekss jsennystaso