unix高级环境编程 例子 代码实现练习 第十一章:线 程

来源:互联网 发布:小黑板软件 编辑:程序博客网 时间:2024/05/22 14:26

程序清单 11-1 打印线程ID

/** * 程序清单 11-1 打印线程ID P290 * * zy: * * 创建了一个线程并且打印了ID * * 编译命令:gcc test2.c -lpthread * 因为pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a。 * 运行结果:asd@asd-desktop:~/workspace/test/src$ ./a.outmain 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.outthread2 exitthread1 returningthread1 exit code 2thread2 exit code 1asd@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.outthread1 : structure at 0xb75a0350 foo.a= 1 foo.b= 2 foo.c= 3 foo.d= 4start thread 2thread 2 :ID is -1218835648parent: structure at 0xb75a0350 foo.a= 0 foo.b= -1218835648 foo.c= -1218835648 foo.d= -1217097740asd@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.outstart thread 2thread 2 startthread 2 push completethread 1 startthread 1 push completethread1 exit code 1cleanup: thread 2 second handlercleanup: thread 2 first handlerthread2 exit code 2asd@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);}



0 0
原创粉丝点击