写出Linux下C编程的线程创建函数用法,LINUX c编程 线程应用(一)——创建分离线程和延迟函数...

通过线程设计一个延迟运行的函数,但不挂起当前线程。

掌握要点:

1.怎么创建一个脱离线程。

2.怎么用select()实现一个延迟函数。

说明:

timeout(int,void *(*)(void*),void *);在指定秒数为负数或任何线程执行函数失败时都直接运行指定的延迟执行函数。

1.[代码][C/C++]代码

#include "unp.h"

/*以下是为使用超时函数定义的接口数据和函数*/

typedef void *(*pthread_f)(void *);

typedef struct toinfo_t{

pthread_f to_func;

void*to_args;

timeval_ttv;

}toinfo_t;

void*timeout_ext(toinfo_t *args){

int n;

__again:

n=select(1,0,0,0,&args->tv);

if(n==-1){

if(errno!=EINTR)

print_err("select()");

fprintf(stderr,"select() interrupt by sigint\n");

goto __again;

}

args->to_func(args->to_args);

free(args);

return (void*)0;

}

int create_detach_thread(pthread_f func,void *args){

pthread_attr_t attr;

pthread_t tid;

intflag;

charbuf[BUF_ERR_SIZE];

flag=pthread_attr_init(&attr);

if(flag!=0){

fprintf(stderr,"%s error:%s\n","pthread_attr_init()",geterr_str(flag,buf,sizeof(buf)));

goto __err;

}

flag=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

if(flag!=0){

fprintf(stderr,"%s error:%s\n","pthread_attr_setdetachstate()",geterr_str(flag,buf,sizeof(buf)));

goto __err0;

}

flag=pthread_create(&tid,&attr,(pthread_f)func,args);

if(flag!=0){

fprintf(stderr,"%s error:%s\n","pthread_create()",geterr_str(flag,buf,sizeof(buf)));

}

__err0:

flag=pthread_attr_destroy(&attr);

if(flag!=0){

fprintf(stderr,"%s error:%s\n","pthread_attr_destroy()",geterr_str(flag,buf,sizeof(buf)));

flag==0;

}

__err:

return flag;

}

void timeout(int secs,pthread_f func,void *args){

int flag;

pthread_attr_t attr;

toinfo_t *toinfo;

pthread_t tid;

if(secs>0){

toinfo=(toinfo_t*)malloc(sizeof(toinfo_t));

if(toinfo!=NULL){

toinfo->tv.tv_sec=secs;

toinfo->to_args=args;

toinfo->to_func=func;

if(create_detach_thread((pthread_f)timeout_ext,toinfo)==0)

return;

free(toinfo);

}

}

func(args);

return;

}

/*以下用户自定义的函数和数据*/

void *user_timeout_func(timeval_t *args){

timeval_ttv,stv;

if(gettimeofday(&tv,0)==-1)

print_err("gettimeofday()");

stv.tv_sec=tv.tv_sec-args->tv_sec;

if(tv.tv_usec>args->tv_usec){

stv.tv_usec=tv.tv_usec-args->tv_usec;

}

else{

stv.tv_sec-=1;

stv.tv_usec=1*1000000-args->tv_usec+tv.tv_usec;

}

fprintf(stderr,"escape time sec %lu ,msec %lu\n",stv.tv_sec,stv.tv_usec);

}

voidintr_handler(int signo){

return;

}

void *delay(void *args){

int i,j;

for(i=0;i<10000;i++){

for(j=0;i<1000;j++)

;

}

return (void*)0;

}

int main(int argc,char **argv){

timeval_t tv;

sigset_t sm;

int i;

if(argc!=2){

fprintf(stderr,"usage %s \n",argv[0]);

exit(EXIT_FAILURE);

}

handle_signal(SIGINT,intr_handler);

if(gettimeofday(&tv,0)==-1)

print_err("gettimeofday()");

timeout(atoi(argv[1]),(pthread_f)user_timeout_func,&tv);

sigemptyset(&sm);

sigaddset(&sm,SIGINT);

sigsuspend(&sm);

return 1;

}

2.[代码]程序的优化

编译运行以上程序:

gcc -o thread_timeout_func01 thread_timeout_func01.c unp.c -g -w -lpthread

root@U-SERVER:/home/apu/pthread_test# ./thread_timeout_func01 5

^Cselect() interrupt by sigint

^Cselect() interrupt by sigint

escape time sec 5 ,msec 4435

^\Quit

root@U-SERVER:/home/apu/pthread_test#

分析:

1.主线程信号屏蔽为只接收SIGQUIT(Ctrl+\)。

2.当我们按下(Ctrl+C)时其他线程会收到了此信号,select()被中断,且select()不会被系统自动重启,而需要我们从用户应用层去重启,重启后select()的timeval_t参数变为剩余时间。所用超时时间的控制是比较精确的(我们也可以从应用层控制,但效果不如select()从内核控制来得好)。

3.但超时结束时,可以看出时间流逝是5秒4435微秒,几乎接近5秒这个单位。

以上测试主程序,是在2个线程的情况下测试的。现在我们来模拟一个繁忙的系统,即CPU的时间片会快速在进程、线程间切换:

voidintr_handler(int signo){

fprintf(stderr,"tid %lu caught sigint\n",(unsigned long)pthread_self());

return;

}

void *delay(void *args){

int i,j;

for(i=0;i<10000;i++){

for(j=0;i<1000;j++)

;

}

fprintf(stderr,"one thread end\n");

return (void*)0;

}

int main(int argc,char **argv){

timeval_t tv;

sigset_t sm;

int i;

if(argc!=3){

fprintf(stderr,"usage %s \n",argv[0]);

exit(EXIT_FAILURE);

}

handle_signal(SIGINT,intr_handler);

for(i=0;i

create_detach_thread(delay,0);

}

if(gettimeofday(&tv,0)==-1)

print_err("gettimeofday()");

fprintf(stderr,"start runing timeout()\n");

timeout(atoi(argv[1]),(pthread_f)user_timeout_func,&tv);

sigemptyset(&sm);

sigaddset(&sm,SIGINT);

sigsuspend(&sm);

return 1;

}

创建多个分离线程,每个线程都循环执行一个空语句,已保证CPU在切换。

编译并运行。

root@U-SERVER:/home/apu/pthread_test# gcc -o thread_timeout_func01 thread_timeout_func01.c unp.c -g -w -lpthread

root@U-SERVER:/home/apu/pthread_test# ./thread_timeout_func01 10 10

start runing timeout()

^Ctid 3075857264 caught sigint

^Ctid 3075857264 caught sigint

^Ctid 3075857264 caught sigint

escape time sec 10 ,msec 17164

^\Quit

root@U-SERVER:/home/apu/pthread_test# ./thread_timeout_func01 10 100

start runing timeout()

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Cescape time sec 10 ,msec 141697

tid 3076782960 caught sigint

^\Quit

root@U-SERVER:/home/apu/pthread_test#

说明:

1.信号只会被其中一个线程接收,且是固定的(如果第一个接收信号的线程没有结束)。

2.从select()没有被中断可以看出,优先运行的线程优先接收信号。

3.系统越繁忙,计时越不精准。

修改接口函数timeout(),timeout_ext(),添加时间流逝控制,增加精确度。

void timeout(int secs,pthread_f func,void *args){

timeval_t tv;

int flag;

pthread_attr_t attr;

toinfo_t *toinfo;

pthread_t tid;

if(secs>0){

if(gettimeofday(&tv,0)==-1)

print_err("gettimeofday()");

tv.tv_sec+=secs;

toinfo=(toinfo_t*)malloc(sizeof(toinfo_t));

if(toinfo!=NULL){

bcopy(&tv,&toinfo->tv,sizeof(timeval_t));

toinfo->to_args=args;

toinfo->to_func=func;

if(create_detach_thread((pthread_f)timeout_ext,toinfo)==0)

return;

free(toinfo);

}

}

func(args);

return;

}

void*timeout_ext(toinfo_t *args){

timeval_ttv,stv;

int n;

if(gettimeofday(&tv,0)==-1)

print_err("gettimeofday()");

if(args->tv.tv_sec>tv.tv_sec ||(args->tv.tv_sec==tv.tv_sec && args->tv.tv_usec>tv.tv_usec)){

stv.tv_sec=args->tv.tv_sec-tv.tv_sec;

if(args->tv.tv_usec>tv.tv_usec){

stv.tv_usec=args->tv.tv_usec-tv.tv_usec;

}

else{

stv.tv_sec-=1;

stv.tv_usec=1*1000000+args->tv.tv_usec-tv.tv_usec;

}

__again:

n=select(1,0,0,0,&stv);

if(n==-1){

if(errno!=EINTR)

print_err("select()");

fprintf(stderr,"select() interrupt by sigint\n");

goto __again;

}

}

args->to_func(args->to_args);

free(args);

return (void*)0;

}

编译运行:

root@U-SERVER:/home/apu/pthread_test# ./thread_timeout_func01 10 100

start runing timeout()

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Ctid 3076782960 caught sigint

^Cescape time sec 10 ,msec 141697

tid 3076782960 caught sigint

^\Quit

root@U-SERVER:/home/apu/pthread_test# gcc -o thread_timeout_func thread_timeout_func.c unp.c -g -w -lpthread

root@U-SERVER:/home/apu/pthread_test# ./thread_timeout_func 10 100

start runing timeout()

^Ctid 3076725616 caught sigint

escape time sec 10 ,msec 8565

^\Quit

root@U-SERVER:/home/apu/pthread_test#

从结果来看精准度得到了很大的提高,如果是秒级别的延迟。这点精度丢失不算什么,但如果是毫秒,甚至微妙级别的,这样的精度丢失就尤为严重了。100个线程(进程)运行,误差不到10毫秒,还是非常不错的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值