APUE函数笔记九: 线程

原创 2012年03月30日 00:49:05

第十一章  线程:

#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;
}


APUE读书笔记-第二章 unix标准及实现

《程序员的自我修养》这本书的读书笔记就先告一段落了,最后一章的运行时库实现也没有实现,有机会再补上吧。今天又回到APUE,第一章也不给大家分享什么了,这本书的读书笔记从第二章开始。好了开始今天的主题,...
  • u012927281
  • u012927281
  • 2016年06月14日 15:51
  • 306

APUE(3rd) 学习笔记:01:第一章:UNIX基础知识

一个简单的学习笔记,主要用于记录书中的要点,自己的理解&疑问,以及课后习题;最重要的是,以此作为自我监督的手段,督促自己不要半途而废。 一、Unix体系结构 严格意义上来说,可将操作系统定义为一种...
  • kokawan1017
  • kokawan1017
  • 2015年04月23日 23:30
  • 258

读书笔记-APUE第三版-(7)进程环境

本章关注单进程运行环境:启动&终止、参数传递和内存布局等。 进程启动终止 如图所示: 启动:内核通过exec函数执行程序,在main函数运行之前,会调用启动例程(start-...
  • cargogo
  • cargogo
  • 2014年05月06日 13:24
  • 1611

读书笔记-APUE第三版-(4)文件和目录

stat函数返回文件信息,本章内容围绕存储在stat结构体中的各种文件属性展开。(注:ls -l会调用stat函数,显示文件相关信息。) struct stat { mode_t st_mo...
  • cargogo
  • cargogo
  • 2014年04月25日 17:38
  • 1042

APUE学习笔记——10.18 system函数 与waitpid

system函数 system函数用方便在一个进程中执行命令行(一行shell命令)。
  • Windeal
  • Windeal
  • 2014年09月04日 10:45
  • 951

线程安全函数和可重入函数

在多线程编程和信号处理过程中,经常会遇到可重入(reentrance)与线程安全(thread-safe)。 很多人纠结于reentrance和thread-safe两个概念理解纠缠不清。我想救我对...
  • youngkingyj
  • youngkingyj
  • 2014年04月24日 20:13
  • 1334

APUE16章的运行示例16-14

博客声明:http://blog.csdn.net/up_seeker/article/details/8887257 参考文章:http://blog.csdn.net/andyxie407/art...
  • Up_Seeker
  • Up_Seeker
  • 2014年01月12日 20:06
  • 1021

apue 函数原型 ---线程

#include 1.int pthread_equal(pthread_t tid1,pthread_t tid2);比较两个线程ID,若相等返回非0数值,否则返回0 2.pthread...
  • qq_24395625
  • qq_24395625
  • 2017年06月05日 20:23
  • 38

APUE笔记 线程

概念 一个线程拥有表示线程执行环境的信息: 线程id 一组寄存器值,栈, 信号屏蔽字, errno变量 线程私有变量 进程的所有信息对线程共享 代码段,栈,堆,文件描述符! 线程测试宏_P...
  • CSLDBLYDX
  • CSLDBLYDX
  • 2015年04月18日 17:04
  • 180

APUE学习笔记——线程

采用多线程模式可以采用同步编程,而非异步编程,可以简化编程;多个进程间可以很方便的共享数据; 可以通过pthread_self获得自身的线程ID。线程ID只在进程内部唯一。 新创建线程不能保证那个线程...
  • chgaowei
  • chgaowei
  • 2013年03月02日 21:43
  • 2794
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:APUE函数笔记九: 线程
举报原因:
原因补充:

(最多只允许输入30个字)