【APUE】线程


进程所有的信息对该进程所有的线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符

 
 
int pthread_equal(pthread_t tid1, pthread_t tid2)
对两个线程ID进行比较
pthread_t pthread_self(void)
返回本线程的id
当线程需要识别以线程id作为表示的数据结构时,两个函数可以一起使用。比如可以将工作任务放在一个队列中,用线程id来控制每个工作线程处理哪些作业。
 
 
 
  • 线程创建
int pthread_create(pthread_t *tidp,  指向的内存单元被设置为新的创建的线程的id
                        const pthread_attr_t *attr,   设置不同的线程属性 可以为NULL
                        void *(start_rtn)(void *),  新创建的线程的起始运行的地址
                        void *arg)   向函数传递的参数
 
#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 (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;
    err = pthread_create(&ntid, NULL, thr_fn, NULL);
    printids("main thread: ");
    sleep(1);
    exit(0);
}

 

 
注意编译时需要加gcc thread.c -lpthread
运行结果是:
main thread:  pid 5650 tid 2893024928 (0xac700ea0)
new thread:  pid 5650 tid 1082132832 (0x40800960)
 
 
 
  • 线程终止
如果任一线程调用了exit那么整个进程都会终止。类似的,如果信号的默认动作是终止进程,那么把该信号发送到线程也会终止进程
 
单个线程退出的方式
1)从启动例程中返回,返回值是线程的退出码
2)线程可以被同一进程中的其他线程取消
3)线程调用pthread_exit
 
void pthread_exit(void *rval_ptr)
参数是一个无类型指针,与传递给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针
 
int pthread_join(pthread_t thread, void **rval_ptr)
调用线程将一直阻塞,直到线程调用pthread_exit,从启动例程中返回或者被取消。
rval_ptr包含返回码
可以通过本函数自动把线程置于分离状态,这样资源就可以恢复。
如果rval_ptr=NULL,就等待线程结束,但是并不获取线程的终止状态
 
 
#include"apue.h"
#include<pthread.h>

void *thr_fn1(void *arg)
{
    printf("thread1 returnning \n");
    return ((void *)1);
}

void *thr_fn2(void *arg)
{
    printf("thread2 returnning \n");
    return ((void *)2);
}

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

    pthread_create(&tid1, NULL, thr_fn1, NULL);
    pthread_create(&tid2, NULL, thr_fn2, NULL);
    pthread_join(tid1, &tret);
    printf("thread 1 exit code %d\n", (int)tret);
    pthread_join(tid2, &tret);
    printf("thread 2 exit code %d\n", (int)tret);
    exit(0);
}

 

 
int pthread_cancel(pthrea_t tid);
线程请求取消同一进程中的其他线程。
 
 
线程也可以安排他退出时需要调用的函数,类似于atexit,叫做线程清理处理程序
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
void pthread_cleanup_pop(int execute);
 
#include"apue.h"
#include<pthread.h>

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

void *thr_fn1(void *arg)
{
    printf("thread 1 start\n");
    pthread_cleanup_push(cleanup, "thread 1 first handler");
    pthread_cleanup_push(cleanup, "thread 1 second handler");
    printf("thread 1 push over\n");
    if(arg)
        return((void *)1);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    printf("thread1 returnning \n");
    return ((void *)1);
}

void *thr_fn2(void *arg)
{
    printf("thread 2 start\n");
    pthread_cleanup_push(cleanup, "thread 2 first handler");
    pthread_cleanup_push(cleanup, "thread 2 second handler");
    printf("thread 2 push over\n");
    if(arg)
        pthread_exit((void *)2);
    pthread_cleanup_pop(0);
    pthread_cleanup_pop(0);
    printf("thread2 returnning \n");
    //return ((void *)2);
    pthread_exit((void *)2);
}

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

    pthread_create(&tid1, NULL, thr_fn1, (void *)1);
    pthread_create(&tid2, NULL, thr_fn2, (void *)2);
    pthread_join(tid1, &tret);
    printf("thread 1 exit code %d\n", (int)tret);
    pthread_join(tid2, &tret);
    printf("thread 2 exit code %d\n", (int)tret);
    exit(0);
}

 

 
运行结果:
thread 2 start
thread 2 push over
thread 1 start
thread 1 push over
thread 1 exit code 1
clean up thread 2 second handler 
clean up thread 2 first handler 
thread 2 exit code 2
 
从运行结果中可以看出,如果线程是从他的启动例程中返回而终止的话,那么他的清理程序就不会被调用。
 
int pthread_detach(pthread_t tid)
使线程处于分离状态。当处于分离状态时,线程的底层存储资源可以再线程终止时被立即收回。当线程被分离时,不能用join函数等待他的终止状态,调用产生失败。
 
 
---------------------------------------------------------------------------
 
  • 线程同步
1)可以通过pthread的互斥锁接口保护数据,确保同一时刻只有一个线程访问数据。
互斥变量用pthread_mutex_t数据类型来表示,在使用互斥变量之前,必须将他初始化,可以设置为常量PTHREAD_MUTEX_INITIALIZER
也可以调用函数
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
int pthread_mutex_destroy(pthread_mutex_t *mutex);
动态分配后需要destroy
 
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
对资源加锁和解锁
 
 
2)读写锁
比互斥锁更灵活,有三种加锁状态:读模式下加锁、写模式下加锁、不加锁状态
一次只有一个锁可以占据写模式,但是可以 有多个锁占据读模式
初始化和销毁和互斥锁类似
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr *attr)
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
 
加锁和解锁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
 
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
 
 
3)条件变量
给多个线程提供了一个会合的场所。条件变量和互斥量一起使用时,允许线程以无竞争方式等待特定的条件发生。
条件本身是由互斥量保护的。线程在改变条件状态前必须首先锁住互斥量
类似的也有初始化和销毁函数
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr)
int pthread_cond_destroy(pthread_cond_t *cond)
 
等待条件变真,如果在等待时间内不能满足,则会返回错误
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timewait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *timeout)
 
等条件时满足时唤醒线程
int pthread_cond_signal(pthread_cond_t *cond)
int pthread_cond_broadcast(pthread_cond_t *cond)
 
 
posted @ 2012-09-20 12:46  w0w0  阅读(214)  评论(0编辑  收藏  举报