AUPE学习第十一章------线程

一个进程中的所有线程都可以访问该进程的组成部件。用同步机制防止多个线程查看到不一致的共享资源。

11.2线程概念

线程包含了表示进程内执行环境必须的信息,其中包括进程中标识线程的线程ID、一组寄存器、栈、调度优先级和策略、信号屏蔽字

、errno变量以及线程的私有数据。

进程的所有信息对该进程的所有线程都是共享的。

线程ID的数据类型是pthread_t数据类型,可以用下面的函数比较两个线程ID。

int   pthread_equal(  pthread_t   tid1,   pthread_t  tid2);


线程可以通过调用pthread_self函数获得自身的线程ID。

#include  <pthread.h>

pthread_t  pthread_self( void )

11.4 线程创建

在传统UNIX进程模型中,一个进程只有一个控制线程。我们可以通过pthread_create函数创建。

#include <pthread.h>

int   pthread_create([pthread_t   *restrict  tidp,  const  pthread_attr_t  *restrict   attr,  void  *(*start_rtn)(void),  void  *restrict   arg)

当成功返回后,tidp指向的内存单元被设置为新创建线程的线程ID。

attr参数用于保存不同的线程属性。

下面的实例打印进程ID、新的线程ID、初始线程ID:

[root@localhost apue]# gcc page290.c -l pthread
[root@localhost apue]# ./a.out 
main thread: pid 1696 tid 3086464704 (oxb7f7b6c0)
new thread:  pid 1696 tid 3086461840 (oxb7f7ab90)
[root@localhost apue]# cat page290.c 
#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 %u tid %u (ox%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;
        err = pthread_create(&ntid, NULL,thr_fn, NULL);
        if(err != 0)
                err_quit("can't create thread:%s\n",strerror(err));
        printids("main thread:");
        sleep(1);
        exit(0);
}

11.5线程终止

如果进程中任一线程调用exit、_Exit、_exit,那么整个进程就会终止。

线程可以调用pthread_exit来终止:

#include <pthread.h>

void  pthread_exit(void  *rual_ptr);

这个函数的参数是值是返回给启动例程的。

其他线程可以通过pthread_join来访问上面的参数的指针。

int   pthread_join(pthread_t  thread,  void   **rual_ptr)

[root@localhost apue]# gcc page292.c -l pthread
[root@localhost apue]# ./a.out 
thread 1 returning
thread 2 exiting
thread 1 exit code 1
thread 2 exit code 2
[root@localhost apue]# cat page292.c 
#include "apue.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");
        pthread_exit((void *)2);
}

int main(void)
{
        int err;
        pthread_t tid1,tid2;
        void *tret;
        err = pthread_create(&tid1, NULL, thr_fn1,NULL);
        if(err != 0)
                err_quit("can't create thread 1:%s\n", strerror(err));
        err = pthread_create(&tid2, NULL, thr_fn2,NULL);
        if(err != 0)
                err_quit("can't create thread 2:%s\n", strerror(err));

        err = pthread_join(tid1, &tret);
        if(err != 0)
                err_quit("can't join with thread 1: %s\n", strerror(err));
        printf("thread 1 exit code %d\n", (int)tret);
        err = pthread_join(tid2, &tret);
        if(err != 0)
                err_quit("can't join with thread 2: %s\n", strerror(err));
        printf("thread 2 exit code %d\n", (int)tret);

        return 0;
}

可以通过下面函数来请求取消进程中的其他线程:

int   pthread_cancle(pthread_t   tid)


可以给线程安排线程清理处理程序:

#include  <pthread.h>

void   pthread_cleanup_push(void   (*rtn)(void  *),   void  *arg)

void  pthread_cleanup_pop(int  execute)


可以用下面的函数让线程进入分离状态:

int   pthread_detach( pthread_t   tid)

如果一个线程没有进入分离状态,则可以用pthread_join来保存线程的终止状态。


11.6线程同步

线程同步可以通过互斥量、读写锁、条件变量来实现线程之间的同步机制。

当一个线程可以修改变量,而其他线程也可以读取或者修改这个变量的时候,就需要线程同步以确保他们访问的变量

是有效的值。

互斥量:本质上是一把锁,在访问共享资源前对互斥量进行加锁,在访问完以后释放互斥量上的锁。

互斥变量可以用pthread_mutex_t数据类型来表示,在使用互斥变量以前,必须首先对它进行初始化。

可以用下面两个函数对动态初始化的互斥变量初始化和释放:

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

如果使用默认的属性初始化互斥量,只需把attr变量设置为NULL。


可以用下面三个函数对互斥量加锁和解锁:

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

第二个和第一个的区别是:第二个如果不能上锁,不进入阻塞状态,第一个进入阻塞状态直到能上锁。


[root@localhost apue]# cat page300.c 
#include <stdlib.h>
#include <pthread.h>

struct foo{
        int f_count;
        pthread_mutex_t f_lock;
};

struct foo * foo_alloc(void)
{
        struct foo *fp;
        if ((fp = malloc(sizeof(struct foo))) != NULL)
        {
                fp->f_count = 1;
                if (pthread_mutex_init(&fp->f_lock, NULL) != 0)
                {
                        free(fp);
                        return(NULL);
                }
        }
        return (fp);
}

void foo_hold(struct foo *fp)
{
        pthread_mutex_lock(&fp->f_lock);
        fp->f_count++;
        pthread_mutex_unlock(&fp->f_lock);
}

void foo_rele(struct foo *fp)
{
        pthread_mutex_lock(&fp->f_lock);
        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);
        }
}

读写锁和互斥量类似,不过读写锁允许更高的并发性。

当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。

读写锁非常适合对数据结构的读次数远大于写的情况。

可以用下面的函数用于读写锁的初始化和释放:

#include <phtread.h>

int  pthread_rwlock_init(  pthread_rwlock_t   *restrict   rwlock)

int   pthread_rwlock_destroy( pthread_rwlock_t   *rwlock)


可以用下面的函数用于读写锁的加锁和解锁:

#include <pthread.h>

int  pthread_rwlock_rdlock( pthread_rwlock_t  *rwlock)

int  pthread_rwlock_wrlock(pthread_rwlock_t   *rwlock)

int  pthread_rwlock_unlock( pthread_rwlock_t   *rwlock)


[root@localhost apue]# cat page307.c 
#include <stdlib.h>
#include <pthread.h>

struct job{
        struct job *j_next;
        struct job *j_prev;
        pthread_t j_id;
};

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

int queue_init(struct queue *qp)
{
        int err;
        qp->q_head = NULL;
        qp->q_tail = NULL;
        err = pthread_rwlock_init(&qp->q_lock, NULL);
        if(err != 0)
                return (err);
        return (0);
}


void job_insert(struct queue *qp, struct job *jp)
{
        pthread_rwlock_wrlock(&qp->q_lock);
        jp->j_next = qp->q_head;
        jp->j_prev = NULL;
        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);
}

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

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

struct job * job_find(struct queue *qp, pthread_t id)
{
        struct job *jp;
        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))
                        break;
        pthread_rwlock_unlock(&qp->q_lock);
        return (jp);
}

条件变量时线程可用的另一种同步机制,条件变量和互斥量一起使用,运行线程以无竞争的方式等待特定的条件发生。

条件变量在使用前必须用pthread_cond_init初始化.

#include  <pthread.h>

int  pthread_cond_init( pthread_cond_t  *restrict  cond,  pthread_condattr_t   *restrict  attr);

int   pthread_cond_destroy(  pthread_cond_t  *cond)


用下面的函数等待条件变量为真,如果在给定的时间内不嫩满足,生成一个代表出错码的返回变量。

#include  <pthread.h>

int  pthread_cond_wait( pthread_cond_t  *restrict   cond,  pthread_mutex_t   *restrict  mutex)

函数中的第二个参数是一个互斥量,对条件进行保护。
























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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值