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

程序清单 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);
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值