thread 的組成
UNIX Thread Standard
#include<pthread.h>
Linux thread implement
pthread_t
這個資料型態表示#include <pthread.h> int pthread_equal(pthread_t tid1, pthread_t tid2); /* Returns: nonzero if equal, 0 otherwise */
#include <pthread.h> pthread_t pthread_self(void); /*Returns: the thread ID of the calling thread*/
#include <pthread.h> int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg); /* Returns: 0 if OK, error number on failure */
#include "apue.h" #include <pthread.h> pthread_t ntid; void printids(const char *s) { pid_t pid; pthread_t tid; pid = getpid(); tid = pthread_self(); printf("%s pid %lu tid %lu (0x%lx)\n", s, (unsigned long)pid, (unsigned long)tid, (unsigned long)tid); } void *thr_fn(void *arg) { printids("new thread: "); return((void *)0); } int main(void) { int err; err = pthread_create(&ntid, NULL, thr_fn, NULL); if (err != 0) { err_exit(err, "can't create thread"); } printids("main thread:"); sleep(1); exit(0); }
$ ./fig11.2-threadid new thread: pid 3207 tid 3084950416 (0xb7e09b90) main thread: pid 3207 tid 3084953264 (0xb7e0a6b0)
thread termination
thread termination status
#include <pthread.h> void pthread_exit(void *rval_ptr); int pthread_join(pthread_t thread, void **rval_ptr); /* Returns: 0 if OK, error number on failure */
#include <pthread.h> int pthread_detach(pthread_t thread); /* Returns: 0 if OK, error number on failure */
cancelling a thread
#include <pthread.h> int pthread_cancel(pthread_t thread); /* Returns: 0 if OK, error number on failure */
cleanup function
#include <pthread.h> void pthread_cleanup_push(void (*routine)(void *), void *arg); void pthread_cleanup_pop(int execute);
comparison process and thread function
Process | Thread | Description |
---|---|---|
fork | pthread_create | create a new flow of control |
exit | pthread_exit | exit from an existing flow of control |
waitpid | pthread_join | get exit status from flow of control |
atexit | pthread_cleanup_push | register function to be called at exit from flow of control |
getpid | pthread_self | get ID for flow of control |
abort | pthread_cancel | request abnormal termination of flow of control |
Mutexes
pthread mutexes
initialize and destroy
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); int pthread_mutex_destroy(pthread_mutex_t *mutex); /* Returns: 0 if OK, error number on failure */ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
lock and unlock
#include <pthread.h> int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); /* Returns: 0 if OK, error number on failure */
#include <stdlib.h> #include <pthread.h> struct foo { int f_count; pthread_mutex_t f_lock; int f_id; /* ... more stuff here ... */ }; struct foo *foo_alloc(int id) /* allocate the object */ { struct foo *fp; if ((fp = malloc(sizeof(struct foo))) != NULL) { fp->f_count = 1; fp->f_id = id; if (pthread_mutex_init(&fp->f_lock, NULL) != 0) { free(fp); return(NULL); } /* ... continue initialization ... */ } return(fp); } void foo_hold(struct foo *fp) /* add a reference to the object */ { pthread_mutex_lock(&fp->f_lock); fp->f_count++; pthread_mutex_unlock(&fp->f_lock); } void foo_rele(struct foo *fp) /* release a reference to the object */ { pthread_mutex_lock(&fp->f_lock); /* last reference */ if (--fp->f_count == 0) { pthread_mutex_unlock(&fp->f_lock); pthread_mutex_destroy(&fp->f_lock); free(fp); } else { pthread_mutex_unlock(&fp->f_lock); } }
deadlock avoidance
Reader-Writer lock
pthread Reader-Writer Lock
initialize and destroy
#include <pthread.h> int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); /* Returns: 0 if OK, error number on failure */
lock and unlock
#include <pthread.h> int pthread_rwlock_rdlock(pthread_rwlock_t*rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t*rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t*rwlock); int pthread_rwlock_unlock(pthread_rwlock_t*rwlock); /* Returns: 0 if OK, error number on failure */
Condition Variable
pthread condition variable
initialize and destroy
#include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); /* Returns: 0 if OK, error number on failure */ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
wait for the condition
#include <pthread.h> int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
#include <pthread.h> #include <unistd.h> static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; struct node { int n_number; struct node *n_next; } *head = NULL; /* thread_func */ static void cleanup_handler(void *arg) { printf("Cleanup handler of second thread./n"); free(arg); (void)pthread_mutex_unlock(&mtx); } static void *thread_func(void *arg) { struct node *p = NULL; pthread_cleanup_push(cleanup_handler, p); while (1) { pthread_mutex_lock(&mtx); // pthread_cond_wait里的线程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait while (head == NULL) { pthread_cond_wait(&cond, &mtx); /* pthread_cond_wait 會先解除之前的 pthread_mutex_lock 鎖定的 mtx,然後 block 在 queue 休眠,直到再次被喚醒 多數情况下是等待的條件成立而被唤醒,唤醒後,該執行緒會先執行 pthread_mutex_lock(&mtx); 再讀取资源 */ } p = head; head = head->n_next; printf("Got %d from front of queue/n", p->n_number); free(p); pthread_mutex_unlock(&mtx); // 釋放互斥鎖 } pthread_cleanup_pop(0); return 0; } int main(void) { pthread_t tid; int i; struct node *p; pthread_create(&tid, NULL, thread_func, NULL); /*[tx6-main]*/ for (i = 0; i < 10; i++) { p = malloc(sizeof(struct node)); p->n_number = i; pthread_mutex_lock(&mtx); // 需要操作head这个臨界資源,先上鎖, p->n_next = head; head = p; pthread_cond_signal(&cond); pthread_mutex_unlock(&mtx); // 解鎖 sleep(1); } printf("thread 1 wanna end the line.So cancel thread 2./n"); pthread_cancel(tid); // pthread_cancel 是從外部终止子執行緒,子執行緒會在最近的取消點退出執行緒,而在我们的程式中,最近的取消點為 pthread_cond_wait() pthread_join(tid, NULL); printf("All done -- exiting/n"); return 0; }
timed wait
#include <pthread.h> int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); struct timespec { __time_t tv_sec; /* Seconds. */ long int tv_nsec; /* Nanoseconds. */ };
void maketimeout(struct timespec *tsp, long minutes) { struct timeval now; /* get the current time */ gettimeofday(&now); tsp->tv_sec = now.tv_sec; tsp->tv_nsec = now.tv_usec * 1000; /* usec to nsec */ tsp->tv_sec += minutes * 60; /* add the offset to get timeout value */ }
notifications
#include <pthread.h> int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond); /* Returns: 0 if OK, error number on failure */
Barriers
#include <pthread.h> int pthread_barrier_destroy(pthread_barrier_t *barrier); int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count); int pthread_barrier_wait(pthread_barrier_t *barrier);