目錄表

Threads

0x00 Outline


0x01 Introduction


0x02 Thread concepts

thread 的組成

UNIX Thread Standard

Linux thread implement


0x03 Thread identification

#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*/


0x04 Thread Creation

#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)

0x05 Thread termination

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

0x06 Thread synchronization

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);

0x07 參考資料