程序清单 12-1 以分离的状态创建的线程
/**
* 程序清单 12-1 以分离的状态创建的线程 P315
* zy:
* 没什么好说的,说的很清楚了
*
*/
#include <pthread.h>
#include "apue.h"
int makethread(void *(*fn)(void *),void *arg){
int err;
pthread_t tid;
pthread_attr_t attr;
err=pthread_attr_init(&attr);
if(err!=0){
return(err);
}
err= pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if(err==0){ //成功了返回0
err=pthread_create(&tid,&attr,fn,arg);
}
pthread_attr_destroy(&attr);
return (err);
}
程序清单 12-2 使用递归互斥量
/**
* 程序清单 12-2 使用递归互斥量 P321
* zy:
* 确实使用了递归锁,但是我看不出为什么必须使用递归锁
* 经过大量思考,大概因为323页的一段话
* 因为
* timetou需要互斥量来访问条件
* retry需要原子操作
*
* 此外,完整定时操作的nanosleep函数是关键,它可以让线程暂停
*
*/
#include <pthread.h>
#include "apue.h"
#include <time.h>
#include <sys/time.h>
int makethread(void *(*fn)(void *),void *arg){
int err;
pthread_t tid;
pthread_attr_t attr;
err=pthread_attr_init(&attr);
if(err!=0){
return(err);
}
err= pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
if(err==0){ //成功了返回0
err=pthread_create(&tid,&attr,fn,arg);
}
pthread_attr_destroy(&attr);
return (err);
}
struct to_info{
void (* to_fn)(void *);
void *to_arg;
struct timespec to_wait;
};
#define SECTONSEC 1000000000 /*秒转化为纳秒*/
#define USECTONSEC 1000 /*微妙到纳秒*/
void *timeout_helper(void *arg){
struct to_info *tip;
tip=(struct to_info *)arg;
nanosleep(&tip->to_wait,NULL); //这个函数功能是暂停某个线程直到你规定的时间后恢复,第一个就是你要暂停的时间
(*tip->to_fn)(tip->to_arg);//这是一句函数在调用
return 0;
}
void timeout(const struct timespec *when,void (*func)(void *),void *arg){
struct timespec now;
struct timeval tv;
struct to_info *tip;
int err;
gettimeofday(&tv,NULL);condition
now.tv_sec=tv.tv_sec;
now.tv_nsec=tv.tv_usec*USECTONSEC;
if(when->tv_sec>now.tv_sec||
(when->tv_sec==now.tv_sec&&when->tv_nsec>now.tv_nsec)){
tip=malloc(sizeof(struct to_info));
if(tip!=NULL){
tip->to_fn=func;
tip->to_arg=arg;
tip->to_wait.tv_sec=when->tv_sec-now.tv_sec;
if( when->tv_nsec >= now.tv_nsec ){
tip->to_wait.tv_nsec = when->tv_nsec-now.tv_nsec;
}else{
tip->to_wait.tv_sec--;
tip->to_wait.tv_nsec=SECTONSEC-now.tv_nsec+when->tv_nsec;
}
err=makethread(timeout_helper,(void *)tip);
if(err==0)
return;
}
}
/*
* 如果时间到了,now>=when,或者malloc失败了,或者我们不能创建函数,我们只需要现在调用函数
*/
(*func)(arg);
}
pthread_mutexattr_t attr;
pthread_mutex_t mutex;
void retry(void *arg){
pthread_mutex_lock(&mutex);
/*执行步骤*/
pthread_mutex_unlock(&mutex);
}
int main(void){
int err,condition,arg;
struct timespec when;
if((err=pthread_mutexattr_init(&attr))!=0){
err_exit(err,"pthread_mutexattr_init failed");
}
if((err=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE))!=0){
err_exit(err,"can't set recuresive type");
}
if((err=phread_mutex_init(&mutex,&attr))!=0){
err_exit(err,"can't create recursive mutex");
}
/*...*/
pthread_mutex_lock(&mutex);
/*...*/
if(condition){
/*calculate target time "when" */
timeout(&when,retry,(void *)arg);
}
/*...*/
pthread_mutex_unlock(&mutex);
/*...*/
exit(0);
}
程序清单 12-3 getenv 的非可重入版本
/**
* 程序清单 12-3 getenv 的非可重入版本 P326
* zy:
* getenv就是获得环境变量
* 可重入的就是线程安全的
*
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
HOME: /home/asd
USER: asd
asd@asd-desktop:~/workspace/test/src$
*/
#include <string.h>
#include <limits.h>
#include <stdio.h>
//static char envbuf[ARG_MAX]; //明明定义在limits里面,不知道为什么取不了,编译也通不过
static char envbuf[131072]; /* # bytes of args + environ for exec() */
extern char **environ; //环境变量都在这个里面
char *getenv(const char *name){
int i,len;
len = strlen(name);
for (i=0;environ[i]!=NULL;i++){
if((strncmp(name,environ[i],len)==0)
&& environ[i][len]=='='){
strcpy(envbuf,&environ[i][len+1]);
return(envbuf);
}
}
return NULL;
}
void main(){
getenv("HOME");
printf("HOME: %s\n",envbuf);
getenv("USER");
printf("USER: %s\n",envbuf);
}
程序清单 12-4 getenv的可重入(线程安全)版本
/**
* 程序清单 12-4 getenv的可重入(线程安全)版本
*/
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
extern char **environ; //环境变量都在这个里面
pthread_mutex_t env_mutex;
static pthread_once_t init_done=PTHREAD_ONCE_INIT;
static void thread_init(void){
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);//书上解释了,而且中文有错误,我也在博客里指出来了
pthread_mutex_init(&env_mutex,&attr);
pthread_mutexattr_destroy(&attr);
}
int getenv_r(const char *name,char *buf,int buflen){
int i,len,olen;
pthread_once(&init_done,thread_init); //注意一个线程只会调用一次这个函数thread_init函数
len=strlen(name);
pthread_mutex_lock(&env_mutex);
for (i=0;environ[i]!=NULL;i++){
if((strncmp(name,environ[i],len)==0)
&& environ[i][len]=='='){
olen=strlen(&environ[i][len+1]);
if(olen>=buflen){
pthread_mutex_unlock(&env_mutex);
return(ENOSPC);
}
strcpy(buf,&environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
return 0;
}
}
pthread_mutex_unlock(&env_mutex);
return (ENOENT);
}
程序清单 12-5 线程安全的getenv的兼容版本
/**
* 程序清单 12-5 线程安全的getenv的兼容版本 P330
* zy:
* 看书还是要看慢点,不然很有些内容很困惑,回头一看又是没看懂
*
* 虽然使用了一个键
* 但是不同线程访问的私有数据是不同的
*
*/
#include </usr/include/linux/limits.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
static pthread_key_t key;
static pthread_once_t init_done=PTHREAD_ONCE_INIT;
pthread_mutex_t env_mutex = PTHREAD_ONCE_INIT;
extern char **environ; //环境变量都在这个里面
static void thread_init(void){
pthread_key_create(&key,free);
}
int getenv_r(const char *name){
int i,len;
char *envbuf;
pthread_once(&init_done,thread_init); //注意一个线程只会调用一次这个函数thread_init函数
pthread_mutex_lock(&env_mutex);
envbuf = (char *)pthread_getspecific(key);
if(envbuf==NULL){
envbuf=malloc(ARG_MAX); //必须要明确指明:#include </usr/include/linux/limits.h>
if(envbuf==NULL){
pthread_mutex_unlock(&env_mutex);
return (NULL);
}
}
len=strlen(name);
for (i=0;environ[i]!=NULL;i++){
if((strncmp(name,environ[i],len)==0)
&& environ[i][len]=='='){
strcpy(envbuf,&environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
return 0;
}
}
pthread_mutex_unlock(&env_mutex);
return (NULL);
}
程序清单 12-6 同步信号处理
/**
* 程序清单 12-6 同步信号处理 P335
* zy:
* 用了一个专门的线程来处理信号,而不是信号处理程序
*
*
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
^C
interrupt
^C
interrupt
^C
interrupt
^C
interrupt
这里输入了^\
asd@asd-desktop:~/workspace/test/src$
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
int quitflag;
sigset_t mask;
pthread_cond_t wait=PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *thr_fn(void *arg){
int err,signo;
for(;;){
err=sigwait(&mask,&signo);
if(err!=0){
err_exit(err,"sigwait failed");
}
switch (signo) {
case SIGINT:
printf("\ninterrupt\n");
break;
case SIGQUIT:
pthread_mutex_lock(&lock);
quitflag=1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&wait);
break;
default:
printf("unexpected signal %d \n",signo);
exit(1);
break;
}
}
}
int main(void){
int err;
sigset_t oldmask;
pthread_t tid;
sigemptyset(&mask);
sigaddset(&mask,SIGINT);
sigaddset(&mask,SIGQUIT);
if((err=pthread_sigmask(SIG_BLOCK,&mask,&oldmask))!=0){
err_exit(err,"SIG_BLOCK failed");
}
err=pthread_create(&tid,NULL,thr_fn,0);
if(err!=0){
err_exit(err,"can't create thread");
}
pthread_mutex_lock(&lock);
while(quitflag==0){
pthread_cond_wait(&wait,&lock);
}
pthread_mutex_unlock(&lock);
/**
* SIGQUIT已经在这里得到了,请写下其他代码
*/
if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0){
err_sys("SIG_SETMASK error");
}
exit(0);
}
程序清单 12-7 pthread_atfork 实例
/**
* 程序清单 12-7 pthread_atfork 实例 P339
* zy:
* 主要是用fork之后继承了锁,用pthread_atfork来解决就好了
* 运行结果:
asd@asd-desktop:~/workspace/test/src$ ./a.out
thread started ....
parent about to fork
preparing locks...
parent unlock...
parent returned from fork
child unlock...
child returned from fork
asd@asd-desktop:~/workspace/test/src$
*
*/
#include <pthread.h>
#include "apue.h"
#include "error.c"
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
void prepare(void){
printf("preparing locks...\n");
pthread_mutex_lock(&lock1);
pthread_mutex_lock(&lock2);
}
void parent(void){
printf("parent unlock...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void child(void){
printf("child unlock...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void *thr_fun(void *arg){
printf("thread started ....\n");
pause();
return 0;
}
int main(){
int err;
pid_t pid;
pthread_t tid;
if((err=pthread_atfork(prepare,parent,child))!=0){
err_exit(err,"can't install fork handlers");
}
err=pthread_create(&tid,NULL,thr_fun,0);
if(err!=0){
err_exit(err,"can't create thread");
}
sleep(2);
printf("parent about to fork\n");
if((pid=fork())<0){
err_quit("fork failed");
}
else if(pid ==0){
printf("child returned from fork\n");
}else{
printf("parent returned from fork\n");
}
exit(0);
}