APUE函数笔记九: 线程

58 篇文章 0 订阅
49 篇文章 0 订阅

第十一章  线程:

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
    if equal return non-zero, else return 0

#include <pthread.h>
pthread_t pthread_self(void);

#include <pthread.h>
int pthread_create(pthread_t * restrict tidp, 
                   const pthread_attr_t * restrict attr, 
                   void * (*start_rtn)(void *), void * restrict arg);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
void pthread_exit(void * rval_ptr);

#include <pthread.h>
int pthread_join(pthread_t thread, void ** rval_ptr);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
int pthread_cancel(pthread_t tid);
    not wait, just tell the request
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void *), void * arg);
void pthread_cleanup_pop(int execute);
     only when thread exit by pthread_exit/pthread_cancel 
     or pthread_cleanup_pop(non-zero), will call rtn
     pthread_cleanup_pop(0) will unregist the last rtn, but not call it

compare:
        process     thread
        fork()      pthread_create()
        exit()      pthread_exit()
        waitpid()   pthread_join()
        atexit()    pthread_cleanup_push()
        getpid()    pthread_self()
        abort()     pthread_cancel()

#include <pthread.h>
int pthread_detach(pthread_t tid);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t * restrict mutex, 
                       const pthread_mutexattr_t * restrict attr);
    if success return 0, else return error-no, will not modify errno
int pthread_mutex_destroy(pthread_mutex_t * mutex);
    if success return 0, else return error-no, will not modify errno

PTHREAD_MUTEX_INITIALIZER

a mutex/rwlock cannot be lock 2 times in one thread

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t * mutex);
    if success return 0, else return error-no, will not modify errno
int pthread_mutex_trylock(pthread_mutex_t * mutex);
    if success return 0, else return error-no, will not modify errno
int pthread_mutex_unlock(pthread_mutex_t * mutex);
    if success return 0, else return error-no, will not modify errno

lock mutexs need same order, unlock need not

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t * restrict rwlock, 
                        const pthread_rwlockattr_t * restrict attr);
    if success return 0, else return error-no, will not modify errno
int pthread_rwlock_destroy(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno
int pthread_rwlock_wrlock(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno
int pthread_rwlock_unlock(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno
int pthread_rwlock_trywrlock(pthread_rwlock_t * rwlock);
    if success return 0, else return error-no, will not modify errno

#include <pthread.h>
int pthread_cond_init(pthread_cond_t * restrict cond, 
                      pthread_condattr_t * restrict attr);
    if success return 0, else return error-no, will not modify errno
int pthread_cond_destroy(pthread_cond_t * cond);
    if success return 0, else return error-no, will not modify errno

PTHREAD_COND_INITIALIZER

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t * restrict cond, 
                      pthread_mutex_t * restrict mutex);
    if success return 0, else return error-no, will not modify errno
int pthread_cond_timedwait(pthread_cond_t * restrict cond, 
                           pthread_mutex_t * restrict mutex, 
                           const struct timespec * restrict timeout);
    if success return 0, else return error-no, will not modify errno
    struct timespec {
        time_t    tv_sec;  /* seconds */
        long      tv_nsec; /* nanosecods */
    };

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t * cond);
    if success return 0, else return error-no, will not modify errno
int pthread_cond_broadcast(pthread_cond_t * cond);
    if success return 0, else return error-no, will not modify errno

示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void 
printids(const char * s)
{
    pid_t       pid;
    pthread_t   tid;

    pid = getpid();
    tid = pthread_self();
    printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int)pid, 
           (unsigned int)tid, (unsigned int)tid);
}

void * 
thr_fn(void * arg)
{
    printids("new thread: ");
    return ((void *)0);
}

int 
main(void)
{
    int          err;
    pthread_t    ntid;

    err = pthread_create(&ntid, NULL, thr_fn, NULL);
    if (err != 0) {
        printf("cannot create thread: %s\n", strerror(err));
        exit(1);
    }
    printids("main thread: ");
    sleep(1);
    exit(0);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

void * 
thr_fn1(void * arg)
{
    printf("thread 1 returning\n");
    return ((void *)1);
}

void * 
thr_fn2(void * arg)
{
    printf("thread 2 exiting\n");
    return ((void *)2);
}

int 
main(void)
{
    int         err;
    pthread_t   tid1;
    pthread_t   tid2;
    void      * tret;

    if ((err = pthread_create(&tid1, NULL, thr_fn1, NULL)) != 0) {
        printf("cannot create thread 1: %s\n", strerror(err));
        exit(1);
    }
    if ((err = pthread_create(&tid2, NULL, thr_fn2, NULL)) != 0) {
        printf("cannot create thread 2: %s\n", strerror(err));
        exit(1);
    }
    if ((err = pthread_join(tid1, &tret)) != 0) {
        printf("cannot join with thread 1: %s\n", strerror(err));
        exit(1);
    }
    printf("thread 1 exit code %d\n", (int)tret);
    if ((err = pthread_join(tid2, &tret)) != 0) {
        printf("cannot join with thread 2: %s\n", strerror(err));
        exit(1);
    }
    printf("thread 2 exit code %d\n", (int)tret);
    exit(0);
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

void 
cleanup(void * arg)
{
    printf("cleanup %s\n", (char *)arg);
}

/*
 * pop and push implement to be macros
 * pop-count must equit to push-count in a func-block
 * otherwise, error in complile
 */
void * 
thr_fn(void * arg)
{
    int   idx = (int)arg;
    char  buff1[64];
    char  buff2[64]; /* need two buffer! */

    printf("thread %d start\n", idx);
    sprintf(buff1, "thread %d first handler", idx);
    pthread_cleanup_push(cleanup, buff1);
    sprintf(buff2, "thread %d second handler", idx);
    pthread_cleanup_push(cleanup, buff2);
    printf("thread %d push complete\n", idx);
    if (idx == 1) {
        return (arg);
    }
    if (idx == 2) {
        pthread_exit(arg);
    }
    pthread_cleanup_pop(0);
    if (idx == 3) {
        return (arg);
    }
    if (idx == 4) {
        pthread_exit(arg);
    }
    pthread_cleanup_pop(0);
    if (idx == 5) {
        return (arg);
    }
    if (idx == 6) {
        pthread_exit(arg);
    }

    abort();
}

int 
main(void)
{
    int       i;
    int       err;
    pthread_t tid[6];
    void    * tret;

    for (i = 0; i < 6; ++i) {
        if ((err = pthread_create(&tid[i], NULL, thr_fn, (void *)(i + 1))) != 0) {
            printf("cannot create thread %d: %s\n", i + 1, strerror(err));
            exit(1);
        }
    }

    for (i = 0; i < 6; ++i) {
        if ((err = pthread_join(tid[i], &tret)) != 0) {
            printf("cannot join with thread %d: %s\n", i +1, strerror(err));
            exit(1);
        }
    }

    exit(0);
}

#include <stdlib.h>
#include <pthread.h>

struct foo {
    int              f_count;
    pthread_mutex_t  f_lock;
    /* ... more stuff here ... */
};

struct foo * 
foo_alloc(void) /* allocate the object */
{
    struct foo * fp;

    if ((fp = (struct foo *)malloc(sizeof(struct foo))) != NULL) {
        fp->f_count = 1;
        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);
    if (--fp->f_count == 0) { /* last reference */
        pthread_mutex_unlock(&fp->f_lock);
        /* if foo_hold here, what can we do?*/
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    }
    else {
        pthread_mutex_unlock(&fp->f_lock);
    }
}

#include <stdlib.h>
#include <pthread.h>

#define NHASH 29
#define HASH(fp) (((unsigned int)fp) % NHASH)

struct foo {
    int               f_count;
    pthread_mutex_t   f_lock;
    struct foo      * f_next; /* protected by hashlock */
    int               f_id;
    /* ... more stuff here ... */
};

struct foo * fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;

struct foo * 
foo_alloc(void) /* allocate the object */
{
    struct foo * fp;
    int          idx;

    if ((fp = (struct foo *)malloc(sizeof(struct foo))) != NULL) {
        fp->f_count = 1;
        if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
            free(fp);
            return(NULL);
        }
        /* continue initialization */
        idx = HASH(fp);
        pthread_mutex_lock(&hashlock);
        fp->f_next = fh[idx];
        fh[idx] = fp;
        pthread_mutex_unlock(&hashlock);
    }
    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);
}

struct foo * 
foo_find(int id) /* find an existing object */
{
    struct foo * fp;
    int          idx;

    pthread_mutex_lock(&hashlock);
    for (idx = 0; idx < NHASH; ++idx) {
        for (fp = fh[idx]; fp != NULL; fp = fp->f_next) {
            if (fp->f_id == id) {
                foo_hold(fp);
                break;
            }
        }
        if (fp != NULL) {
            break;
        }
    }
    pthread_mutex_unlock(&hashlock);
    return(fp);
}

void 
foo_rele(struct foo * fp) /* release a reference to the object */
{
    struct foo * tfp;
    int          idx;

    pthread_mutex_lock(&fp->f_lock);
    if (fp->f_count == 1) { /* last reference */
        pthread_mutex_unlock(&fp->f_lock);
        pthread_mutex_lock(&hashlock);
        pthread_mutex_lock(&fp->f_lock);
        /* need to recheck the condition */
        if (--fp->f_count == 0) {
            /* remove from list */
            idx = HASH(fp);
            tfp = fh[idx];
            if (tfp == fp) {
                fh[idx] = fp->f_next;
            }
            else {
                while (tfp->f_next != fp) {
                    tfp = tfp->f_next;
                }
                tfp->f_next = fp->f_next;
            }
            pthread_mutex_unlock(&hashlock);
            pthread_mutex_unlock(&fp->f_lock);
            pthread_mutex_destroy(&fp->f_lock);
            free(fp);
        }
        else {
            pthread_mutex_unlock(&hashlock);
            pthread_mutex_unlock(&fp->f_lock);
        }
    }
    else {
        --fp->f_count;
        pthread_mutex_unlock(&fp->f_lock);
    }
}

#include <stdlib.h>
#include <pthread.h>

#define NHASH 29
#define HASH(fp) (((unsigned int)fp) % NHASH)

struct foo {
    int               f_count; /* protected by hashlock */
    pthread_mutex_t   f_lock;
    struct foo      * f_next; /* protected by hashlock */
    int               f_id;
    /* ... more stuff here ... */
};

struct foo * fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER;

struct foo * 
foo_alloc(void) /* allocate the object */
{
    struct foo * fp;
    int          idx;

    if ((fp = (struct foo *)malloc(sizeof(struct foo))) != NULL) {
        fp->f_count = 1;
        if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
            free(fp);
            return(NULL);
        }
        /* continue initialization */
        idx = HASH(fp);
        pthread_mutex_lock(&hashlock);
        fp->f_next = fh[idx];
        fh[idx] = fp;
        pthread_mutex_unlock(&hashlock);
    }
    return(fp);
}

void 
foo_hold(struct foo * fp) /* add a reference to the object */
{
    pthread_mutex_lock(&hashlock);
    ++fp->f_count;
    pthread_mutex_unlock(&hashlock);
}

struct foo * 
foo_find(int id) /* find an existing object */
{
    struct foo * fp;
    int          idx;

    pthread_mutex_lock(&hashlock);
    for (idx = 0; idx < NHASH; ++idx) {
        for (fp = fh[idx]; fp != NULL; fp = fp->f_next) {
            if (fp->f_id == id) {
                /* do not use foo_hold, will deathlock */
                ++fp->f_count;
                break;
            }
        }
        if (fp != NULL) {
            break;
        }
    }
    pthread_mutex_unlock(&hashlock);
    return(fp);
}

void 
foo_rele(struct foo * fp) /* release a reference to the object */
{
    struct foo * tfp;
    int          idx;

    pthread_mutex_lock(&hashlock);
    if (--fp->f_count == 0) { /* last reference */
        /* remove from list */
        idx = HASH(fp);
        tfp = fh[idx];
        if (tfp == fp) {
            fh[idx] = fp->f_next;
        }
        else {
            while (tfp->f_next != fp) {
                tfp = tfp->f_next;
            }
            tfp->f_next = fp->f_next;
        }
        pthread_mutex_unlock(&hashlock);
        pthread_mutex_destroy(&fp->f_lock);
        free(fp);
    }
    else {
        pthread_mutex_unlock(&hashlock);
    }
}

#include <stdlib.h>
#include <pthread.h>

struct job {
    struct job * j_prev;
    struct job * j_next;
    int          j_id; /* tells which thread handles this job */
    /* ... more stuff here ... */
};

struct queue {
    struct job *     q_head;
    struct job *     q_tail;
    pthread_rwlock_t q_lock;
};

/*
 * initialize a queue
 */
int 
queue_init(struct queue * qp)
{
    int err;

    if ((err = pthread_rwlock_init(&qp->q_lock, NULL)) != 0) {
        return(err);
    }
    qp->q_head = NULL;
    qp->q_tail = NULL;
    /* ... continue initialization ... */

    return(0);
}

/*
 * insert a job at the head of the queue
 */
void 
job_insert(struct queue * qp, struct job * jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_prev = NULL;
    jp->j_next = qp->q_head;
    if (qp->q_head != NULL) {
        qp->q_head->j_prev = jp;
    }
    else {
        qp->q_tail = jp;
    }
    qp->q_head = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * append a job on the tail of the queue
 */
void 
job_append(struct queue * qp, struct job * jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    jp->j_next = NULL;
    jp->j_prev = qp->q_tail;
    if (qp->q_tail != NULL) {
        qp->q_tail->j_next = jp;
    }
    else {
        qp->q_head = jp;
    }
    qp->q_tail = jp;
    pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * remove the given job from a queue
 */
void 
job_remove(struct queue * qp, struct job * jp)
{
    pthread_rwlock_wrlock(&qp->q_lock);
    if (qp->q_head == jp) {
        if (qp->q_tail == jp) {
            qp->q_tail = NULL;
        }
        else {
            jp->j_next->j_prev = NULL;
        }
        qp->q_head = jp->j_next;
    }
    else if (qp->q_tail == jp) {
        jp->j_prev->j_next = NULL;
        qp->q_tail = jp->j_prev;
    }
    else {
        jp->j_prev->j_next = jp->j_next;
        jp->j_next->j_prev = jp->j_prev;
    }
    pthread_rwlock_unlock(&qp->q_lock);
}

/*
 * find a job for the given thread ID
 */
struct job * 
job_find(struct queue * qp, pthread_t id)
{
    struct job * jp;

    /* read lock must check */
    if (pthread_rwlock_rdlock(&qp->q_lock) != 0) {
        return(NULL);
    }

    for (jp = qp->q_head; jp != NULL; jp = jp->j_next) {
        if (pthread_equal(jp->j_id, id) != 0) {
            break;
        }
    }
    pthread_rwlock_unlock(&qp->q_lock);

    return(jp);
}

#include <pthread.h>

struct msg {
    struct msg * m_next;
    /* ... more stuff here ... */
};

struct msg * workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;

void 
process_msg(void)
{
    struct msg * mp;

    while (1) {
        pthread_mutex_lock(&qlock);
        while (workq == NULL) {
            pthread_cond_wait(&qready, &qlock);
        }
        mp = workq;
        workq = workq->m_next;
        pthread_mutex_unlock(&qlock);
        /* now process the message mp */
    }
}

void 
enqueue(struct msg * mp)
{
    pthread_mutex_lock(&qlock);
    mp->m_next = workq;
    workq = mp;
    pthread_mutex_unlock(&qlock); /* step 1 */
    pthread_cond_signal(&qready); /* step 2 */
    /*
     * we can switch step 1 and step 2, 
     * they are all right, 
     * but they have diffect effective
     */
}

#include <sys/time.h>
#include <pthread.h>

void 
maketimeout(struct timespec * tsp, long minutes)
{
    struct timeval now;

    /* get the current time */
    gettimeofday(&now, NULL);
    tsp->tv_sec = now.tv_sec;
    tsp->tv_nsec = now.tv_usec * 1000; /* usec to nsec */
    /* add the offset to get timeout value */
    tsp->tv_sec += minutes * 60;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值