Sysprog 14

download Sysprog 14

If you can't read please download the document

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