程序清单 11-1 打印线程ID
/**
* 程序清单 11-1 打印线程ID P290
*
* zy:
*
* 创建了一个线程并且打印了ID
*
* 编译命令:gcc test2.c -lpthread
* 因为pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a。
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
main thread: pid 2571 tid 3075782336 (0xb754b6c0)
new thread: pid 2571 tid 3075779392 (0xb754ab40)
asd@asd-desktop:~/workspace/test/src$
*
* 和书上说的基本一致
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include <string.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(){
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(2);
exit(0);
}
程序清单 11-2 获得线程的推出状态
/**
* 程序清单 11-2 获得线程的推出状态 P292
*
* zy:
* 没什么好说的,非常简单
*
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
thread2 exit
thread1 returning
thread1 exit code 2
thread2 exit code 1
asd@asd-desktop:~/workspace/test/src$
*
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include <string.h>
void *thr_fn2(void *arg){
printf("thread1 returning\n ");
return ((void *)1);
}
void *thr_fn1(void *arg){
printf("thread2 exit\n ");
pthread_exit((void *)2);
}
int main(){
int err;
pthread_t tid1,tid2;
void *tret;
err=pthread_create(&tid1,NULL,thr_fn1,NULL);
if(err!=0){
err_quit("can't create thread1: %s \n",strerror(err));
}
err=pthread_create(&tid2,NULL,thr_fn2,NULL);
if(err!=0){
err_quit("can't create thread2: %s \n",strerror(err));
}
err=pthread_join(tid1,&tret);
if(err!=0){
err_quit("can't join with thread1: %s\n",strerror(err));
}
printf("thread1 exit code %d\n",(int)tret);
err=pthread_join(tid2,&tret);
if(err!=0){
err_quit("can't join with thread2: %s\n",strerror(err));
}
printf("thread2 exit code %d\n",(int)tret);
exit(0);
}
程序清单 11-3 pthread_exit 参数不正确的使用
/**
* 程序清单 11-3 pthread_exit 参数不正确的使用
*
* zy:
* 由于使用了局部变量、自动变量,那个分配在栈上的变量作为返回的结果
* 导致,内容已经改变
*
* 我们可以看到第二个线程是分再次利用之前分配给了线程1的栈上的空间
* 导致我们根本拿不到正确的返回状态
*
*
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
thread1 :
structure at 0xb75a0350
foo.a= 1
foo.b= 2
foo.c= 3
foo.d= 4
start thread 2
thread 2 :ID is -1218835648
parent:
structure at 0xb75a0350
foo.a= 0
foo.b= -1218835648
foo.c= -1218835648
foo.d= -1217097740
asd@asd-desktop:~/workspace/test/src$
*
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include <string.h>
struct foo{
int a,b,c,d;
};
void printfoo(const char *s,const struct foo *fp){
printf(s);
printf(" structure at 0x%x\n",(unsigned)fp);
printf(" foo.a= %d\n",fp->a);
printf(" foo.b= %d\n",fp->b);
printf(" foo.c= %d\n",fp->c);
printf(" foo.d= %d\n",fp->d);
}
void *thr_fn1(void *arg){
struct foo foo={1,2,3,4};
printfoo("thread1 : \n",&foo);
pthread_exit((void *)&foo);
}
void *thr_fn2(void *arg){
printf("thread 2 :ID is %d\n",pthread_self());
pthread_exit((void *)0);
}
int main(){
int err;
pthread_t tid1,tid2;
struct foo *fp;
err=pthread_create(&tid1,NULL,thr_fn1,NULL);
if(err!=0){
err_quit("can't create thread1: %s \n",strerror(err));
}
err=pthread_join(tid1,&fp);
if(err!=0){
err_quit("can't join with thread1: %s\n",strerror(err));
}
sleep(1);
printf("start thread 2\n");
err=pthread_create(&tid2,NULL,thr_fn2,NULL);
if(err!=0){
err_quit("can't create thread2: %s \n",strerror(err));
}
sleep(1);
printfoo("parent:\n",fp);
exit(0);
}
程序清单 11-4 线程清理程序
/**
* 程序清单 11-4 线程清理程序 P295
*
* zy:
* 线程在退出之前可以安排其执行一系列的函数
* thr_fn1中的清理函数是不会执行的,这是因为使用了return。
* 运行结果:
*
asd@asd-desktop:~/workspace/test/src$ ./a.out
start thread 2
thread 2 start
thread 2 push complete
thread 1 start
thread 1 push complete
thread1 exit code 1
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread2 exit code 2
asd@asd-desktop:~/workspace/test/src$
*
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include <string.h>
void cleanup(void *arg){
printf("cleanup: %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 complete\n");
if(arg)
return((void *)1); /*根据我们传入的参数,下面的代码不会执行,在这里就返回了*/
pthread_cleanup_pop(0); /*具体看书吧*/
pthread_cleanup_pop(0);
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 complete\n");
if(arg)
pthread_exit((void *)2);/*根据我们传入的参数,下面的代码不会执行,在这里就返回了*/
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
pthread_exit ((void *)2);
}
int main(){
int err;
pthread_t tid1,tid2;
void *tret;
err=pthread_create(&tid1,NULL,thr_fn1,1);
if(err!=0){
err_quit("can't create thread1: %s \n",strerror(err));
}
printf("start thread 2\n");
err=pthread_create(&tid2,NULL,thr_fn2,1);
if(err!=0){
err_quit("can't create thread2: %s \n",strerror(err));
}
err=pthread_join(tid1,&tret);
if(err!=0){
err_quit("can't join with thread1: %s\n",strerror(err));
}
printf("thread1 exit code %d\n",(int)tret);
err=pthread_join(tid2,&tret);
if(err!=0){
err_quit("can't join with thread2: %s\n",strerror(err));
}
printf("thread2 exit code %d\n",(int)tret);
exit(0);
}
程序清单 11-5 使用互斥量保护数据结构
/**
* 程序清单 11-5 使用互斥量保护数据结构 P300
* zy:
* 这只是一个大致的框架,是利用互排量保护了对共享数据的访问
* 其中count的引入是为了保证,只有当没有对这个数据的访问的最后一个线程不再使用之后
* 才会释放掉内存
* 从这里我可以看出,原来第一次调用的时候会初始化,也会对引用计数加1
*
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include "stdlib.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);
}else{
pthread_mutex_unlock(&fp->f_lock);
}
}
程序清单 11-6 使用两个互斥量
/**
* 程序清单 11-6 使用两个互斥量 P302
* zy:
* 其中一个用于hashlock保护foo数据结构中的fh散列表和f_next散列链字段
* 另一个用于f_lock互斥量对于foo结构中的其他字段的访问
* 注释我都写在书上了,就不过多解释了
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include "stdlib.h"
#define NHASH 29
#define HASH(fp) (((unsigned long )fp)%NHASH) /*这样算出hash值?*/
struct foo *fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; /*保护散列表和f_next字段*/
struct foo{
int f_count; //引用计数,看当前有多少个线程在访问共享数据
pthread_mutex_t f_lock;
struct foo *f_next; //由hashlock保护
int f_id;
/*我认为下面可以填入更多的需要被共享的数据*/
};
struct foo *foo_alloc(void){//只是先为这个给这个数据结构分配内存
struct foo *fp;
int idx;
if((fp=malloc(sizeof(struct foo)))!=NULL){
fp->f_count=1;
if(pthread_mutex_init(&fp->f_lock,NULL)!=0){/*如果初始化失败*/
free(fp);
return(NULL);
}
idx=HASH(fp);
pthread_mutex_lock(&hashlock);
fp->f_next=fp[idx];
fh[idx]=fp;
pthread_mutex_lock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
/*我们接着对foo结果结构进行初始化*/
pthread_mutex_unlock(&fp->f_lock);
}
return(fp);
}
void foo_hold(struct foo *fp){ /*这里就是有一个线程正在使用foo这个结构*/
pthread_mutex_lock(&fp->f_lock);
fp->f_count++; /**/
pthread_mutex_unlock(&fp->f_lock);
}
struct foo *foo_find(int id){ /*找到一个已经存在的id*/
struct foo *fp;
int idx;
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
for(fp= fh[idx];fp!=NULL;fp=fp->f_next){
if(fp->f_id==id){
foo_hold(fp);
break;
}
}
pthread_mutex_unlock(&hashlock);
return (fp);
}
void foo_rele(struct foo *fp){
struct foo *tfp;
int idx;
pthread_mutex_lock(&fp->f_lock);
if(fp->f_count==1){
pthread_mutex_unlock(&fp->f_lock);
pthread_mutex_lock(&hashlock);
pthread_mutex_lock(&fp->f_lock);
if(fp->f_count!=1){
fp->f_count--;
pthread_mutex_unlock(&hashlock);
pthread_mutex_unlock(&fp->f_lock);
}
/*将其从列表中移除*/
idx=HASH(fp);
tfp=fh[idx]; //tfp是表头
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{
fp->f_count--;
pthread_mutex_unlock(&fp->f_lock);
}
}
程序清单 11-7 简化的加锁和解锁
/**
* 程序清单 11-7 简化的加锁和解锁 P304
* zy:
* 让hashlock来保护引用计数,就能大幅度简化问题
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
#include "stdlib.h"
#define NHASH 29
#define HASH(fp) (((unsigned long )fp)%NHASH) /*这样算出hash值?*/
struct foo *fh[NHASH];
pthread_mutex_t hashlock = PTHREAD_MUTEX_INITIALIZER; /*保护散列表和f_next字段*/
struct foo{
int f_count; //引用计数,看当前有多少个线程在访问共享数据
pthread_mutex_t f_lock;
struct foo *f_next; //由hashlock保护
int f_id;
/*我认为下面可以填入更多的需要被共享的数据*/
};
struct foo *foo_alloc(void){//只是先为这个给这个数据结构分配内存
struct foo *fp;
int idx;
if((fp=malloc(sizeof(struct foo)))!=NULL){
fp->f_count=1;
if(pthread_mutex_init(&fp->f_lock,NULL)!=0){/*如果初始化失败*/
free(fp);
return(NULL);
}
idx=HASH(fp);
pthread_mutex_lock(&hashlock);
fp->f_next=fp[idx];
fh[idx]=fp;
pthread_mutex_lock(&fp->f_lock);
pthread_mutex_unlock(&hashlock);
/*我们接着对foo结果结构进行初始化*/
pthread_mutex_unlock(&fp->f_lock);
}
return(fp);
}
void foo_hold(struct foo *fp){ /*这里就是有一个线程正在使用foo这个结构*/
pthread_mutex_lock(&hashlock);
fp->f_count++;
pthread_mutex_unlock(&hashlock);
}
struct foo *foo_find(int id){ /*找到一个已经存在的id*/
struct foo *fp;
int idx;
idx = HASH(fp);
pthread_mutex_lock(&hashlock);
for(fp= fh[idx];fp!=NULL;fp=fp->f_next){
if(fp->f_id==id){
foo_hold(fp);
break;
}
}
pthread_mutex_unlock(&hashlock);
return (fp);
}
void foo_rele(struct foo *fp){
struct foo *tfp;
int idx;
pthread_mutex_lock(&hashlock);
if(--fp->f_count==0){
/*将其从列表中移除*/
idx=HASH(fp);
tfp=fh[idx]; //tfp是表头
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);
}
}
程序清单 11-8 使用读写锁
/**
* 程序清单 11-8 使用读写锁 P308
* zy:
* 是一个框架,代码很好理解
*
*/
#include <pthread.h>
#include "stdlib.h"
struct job {
struct job *j_next;
struct job *j_prev;
pthread_t j_id; //记录哪一个线程处理这个job
/**
* 处理更多线程
*/
};
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){
retrun (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_wrlock(&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_wrlock(&qp->q_lock);
}
/**
* 从队列中移除一个给定的job
*/
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 = jp->j_prev;
if(qp->q_head==jp){
qp->q_tail=NULL;
}
}else{
jp->j_prev->j_next=jp->j_next;
jp->j_next->j_prev=jp->j_prev;
}
pthread_rwlock_wrlock(&qp->q_lock);
}
/**
* 给定一个线程ID,找到相应的JOB
*/
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_rdlock(&qp->q_lock);
return (jp);
}