Linux多线程编程的基本的函数.docx
《Linux多线程编程的基本的函数.docx》由会员分享,可在线阅读,更多相关《Linux多线程编程的基本的函数.docx(19页珍藏版)》请在冰点文库上搜索。
![Linux多线程编程的基本的函数.docx](https://file1.bingdoc.com/fileroot1/2023-5/4/afc40b44-87db-4f9f-9eb7-97e5e7d56cb0/afc40b44-87db-4f9f-9eb7-97e5e7d56cb01.gif)
Linux多线程编程的基本的函数
Linux多线程编程的基本的函数
1线程创建
函数原型:
#include
intpthread_create(pthread_t*restricttidp,constpthread_attr_t*restrict
attr,void*(*start_rtn)(void),void*restrictarg);
返回值:
若是成功建立线程返回0,否则返回错误的编号
形式参数:
pthread_t*restricttidp要创建的线程的线程id指针
constpthread_attr_t*restrictattr创建线程时的线程属性
void*(start_rtn)(void)返回值是void类型的指针函数
vodi*restrictargstart_rtn的行参
例题1:
功能:
测试建立一个新的线程
程序名称:
pthread_test.c
#include
#include
void*create(void*arg)
...{
printf("newthreadcreated.....");
}
intmain(intargc,char*argv[])
...{
pthread_ttidp;
interror;
error=pthread_create(&tidp,NULL,create,NULL);
if(error!
=0)
......{
printf("pthread_createisnotcreated...");
return-1;
}
printf("prthread_createiscreated...");
return0;
}
编译方法:
#gcc-Wall-lpthreadpthread_test.c
因为pthread的库不是linux系统的库,所以在进行编译的时候要加上-lpthread,否则编译不过,会出现下面错误
thread_test.c:
在函数‘create’中:
thread_test.c:
7:
警告:
在有返回值的函数中,程序流程到达函数尾
/tmp/ccOBJmuD.o:
Infunction
'main':
thread_test.c:
(.text+0x4f):
对‘pthread_create’未定义的引用
collect2:
ld返回1
现在我们能建立了一个线程了,我们可以从函数的原型看到,在创建线程的时候,是可以在对我们的函数进行传递参数,在pthread_create的第四个行参。
我们看一下例题2~3.
例题2
功能:
向新的线程传递整形值
程序名称:
pthread_int.c
#include
#include
#include
void*create(void*arg)
...{
int*num;
num=(int*)arg;
printf("createparameteris%d",*num);
return(void*)0;
}
intmain(intargc,char*argv[])
...{
pthread_ttidp;
interror;
inttest=4;
int*attr=&test;
error=pthread_create(&tidp,NULL,create,(void*)attr);
if(error!
=0)
...{
printf("pthread_createiscreatedisnotcreated...");
return-1;
}
sleep
(1);
printf("pthread_createiscreatediscreated...");
return0;
}
编译方法:
gcc-lpthreadthread_int.c-Wall
执行结果:
createparameteris4
pthread_createiscreatediscreated...
例题总结:
可以看出来,我们在main函数中传递的整行指针,传递到我们新建的线程函数中。
在上面的例子可以看出来我们向新的线程传入了另一个线程的int数据,线程之间还可以传递字符串或是更复杂的数据结构。
例题3:
程序功能:
向新建的线程传递字符串
程序名称:
thread_char.c
#include
#include
#include
void*create(void*arg)
...{
char*name;
name=(char*)arg;
printf("argis%s",name);
return(void*)0;
}
intmain(intargc,char*argv[])
...{
char*a="wang";
interror;
pthread_ttidp;
error=pthread_create(&tidp,NULL,create,(void*)a);
if(error!
=0)
...{
printf("pthreadisnotcreated");
return-1;
}
sleep
(1);
printf("pthreadiscreated...");
return0;
}
编译方法:
gcc-Wallthread_char.c-lpthread
执行结果:
argiswang
pthreadiscreated...
例题总结:
可以看出来main函数中的字符串传入了新建里的线程中。
例题4
程序名称:
thread_struct.c
#include
#include
#include
#include/**//*malloc()*/
structtest
...{
inta;
char*s;
};
void*create(void*arg)
...{
structtest*temp;
temp=(structtest*)arg;
printf("test->a==%d",temp->a);
printf("test->s==%s",temp->s);
return(void*)0;
}
intmain(intargc,char*argv[])
...{
pthread_ttidp;
interror;
structtest*b;
b=(structtest*)malloc(sizeof(structtest));
b->a=4;
b->s="wang";
error=pthread_create(&tidp,NULL,create,(void*)b);
if(error!
=0)
...{
printf("phreadisnotcreated...");
return-1;
}
sleep
(1);
printf("pthreadiscreated...");
return0;
}
编译方法:
gcc-Wall-lpthreadthread_struct.c
执行结果:
test->a==4
test->s==wang
pthreadiscreated...
线程包含了标识进程内执行环境必须的信息。
他集成了进程中的所有信息都是对线程进行共享的,包括文本程序、程序的全局内存和堆内存、栈以及文件描述符。
例题5
程序目的:
验证新建立的线程可以共享进程中的数据
程序名称:
thread_share.c
#include
#include
#include
staticinta=4;
void*create(void*arg)
...{
printf("newpthread...");
printf("a==%d",a);
return(void*)0;
}
intmain(intargc,char*argv[])
...{
pthread_ttidp;
interror;
a=5;
error=pthread_create(&tidp,NULL,create,NULL);
if(error!
=0)
...{
printf("newthreadisnotcreate...");
return-1;
}
sleep
(1);
printf("newthreadiscreated...");
return0;
}
编译方法:
gcc-Wall-lpthreadthread_share.c
执行结果:
newpthread...
a==5
newthreadiscreated...
例题总结:
可以看出来,我们在主线程更改了我们的全局变量a的值的时候,我们新建立的线程则打印出来了改变的值,可以看出可以访问线程所在进程中的数据信息。
2、线程的终止
如果进程中任何一个线程中调用exit,_Exit,或者是_exit,那么整个进程就会终止,与此类似,如果信号的默认的动作是终止进程,那么,把该信号发送到线程会终止进程。
线程的正常退出的方式:
(1)线程只是从启动例程中返回,返回值是线程中的退出码
(2)线程可以被另一个进程进行终止
(3)线程自己调用pthread_exit函数
两个重要的函数原型:
#include
voidpthread_exit(void*rval_ptr);
/*rval_ptr线程退出返回的指针*/
intpthread_join(pthread_tthread,void**rval_ptr);
/*成功结束进程为0,否则为错误编码*/
例题6
程序目的:
线程正常退出,接受线程退出的返回码
程序名称:
exit_return.c
#include
#include
#include
void*create(void*arg)
...{
printf("newthreadiscreated...");
return(void*)2;
}
intmain(intargc,char*argv[])
...{
pthread_ttid;
interror;
void*temp;
error=pthread_create(&tid,NULL,create,NULL);
if(error!
=0)
...{
printf("threadisnotcreated...");
return-1;
}
error=pthread_join(tid,&temp);
if(error!
=0)
...{
printf("threadisnotexit...");
return-2;
}
printf("threadisexitcode%d",(int)temp);
sleep
(1);
printf("threadiscreated...");
return0;
}
编译方法:
gcc-Wallexit_return.c-lpthread
执行结果:
newthreadiscreated...
threadisexitcode2
threadiscreated...
线程退出不仅仅可以返回线程的int数值,还可以返回一个复杂的数据结构
例题7
程序目的:
线程结束返回一个复杂的数据结构
程序名称:
exit_thread.c
#include
#include
#include
structtest
...{
inta;
char*b;
};
structtesttemp=
...{
.a=4,
.b="wang"
};
void*create(void*arg)
...{
printf("newthread...");
return(void*)&temp;
}
intmain(intargc,char*argv[])
...{
interror;
pthread_ttid;
structtest*c;
error=pthread_create(&tid,NULL,create,NULL);
if(error!
=0)
...{
printf("newthreadisnotcreated...");
return-1;
}
printf("main...");
error=pthread_join(tid,(void*)&c);
if(error!
=0)
...{
printf("newthreadisnotexit...");
return-2;
}
printf("c->a==%d",c->a);
printf("c->b==%s",c->b);
sleep
(1);
return0;
}
编译方法:
gcc-Wall-lpthreadexit_struct.c
执行结果:
main...
newthread...
c->a==4
c->b==wang
例题总结:
一定要记得返回的数据结构要是在这个数据要返回的结构没有释放的时候应用,如果数据结构已经发生变化,那返回的就不会是我们所需要的,而是藏数据阿。
3、线程标识
函数原型:
#include
pthread_tpthread_self(void);
例题8
程序目的:
实现在新建立的线程中打印该线程的id和进程id
程序名称:
thread_self.c
#include
#include
#include/**//*getpid()*/
void*create(void*arg)
...{
printf("newthread....");
printf("thread_tid==%u",(unsignedint)pthread_self());
printf("threadpidis%d",getpid());
return(void*)0;
}
intmain(intargc,char*argv[])
...{
pthread_ttid;
interror;
printf("Mainthreadisstarting...");
error=pthread_create(&tid,NULL,create,NULL);
if(error!
=0)
...{
printf("threadisnotcreated...");
return-1;
}
printf("mainpidis%d",getpid());
sleep
(1);
return0;
}
编译方法:
gcc-Wall-lpthreadthread_self.c
执行结果:
Mainthreadisstarting...
mainpidis6860
newthread....
thread_tid==3084954544
threadpidis6860
4、线程的处理程序
函数原型:
#include
voidpthread_cleanup_push(void(*rtn)(void*),void*arg);
函数rtn是清理函数,arg是调用参数
voidpthread_cleanup_pop(intexecute);
在前面讲过线程的终止方式,是正常终止还是非正常终止,都会存在一个资源释放的问题,在posix中提供了一组,就是我们上面看的函数进行线程退出的处理函数,有些像在进程中的atexit函数。
释放的方式是指pthread_cleanup_push的调用点到pthread_cleanup_pop之间程序段进行终止。
pthread_cleanup_push()/pthread_cleanup_pop采用先入后出的方式的栈的管理方式,void*rtn(void
*),在执行pthread_cleanup_push()时压入函数栈,多次执行pthread_cleanup_push()形成一个函数链,在执行这个函数链的时候会以反方向弹出,即先入后出。
execute参数表识,是否执行弹出清理函数,当execute=0时不进行弹出清理函数,非零的时候弹出处理函数。
例题9
程序目的:
实现在正常结束线程的时候,进行函数处理
程序名称:
thread_clean.c
编译方法:
执行结果:
thread1start
thread1pushcomplete
thread1exitcode1
thread2start
thread2pushcomplete
cleanup:
thread2secondhandler
cleanup:
thread2firsthandler
thread2exitcode2
gcc-Wall-lpthreadthread_clean.c
#include
#include
#include
void*clean(void*arg)
...{
printf("cleanup:
%s",(char*)arg);
return(void*)0;
}
void*thr_fn1(void*arg)
...{
printf("thread1start");
pthread_cleanup_push(clean,"thread1firsthandler");
pthread_cleanup_push(clean,"thread1secondhadler");
printf("thread1pushcomplete");
if(arg)
...{
return((void*)1);
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return(void*)1;
}
void*thr_fn2(void*arg)
...{
printf("thread2start");
pthread_cleanup_push(clean,"thread2firsthandler");
pthread_cleanup_push(clean,"thread2secondhandler");
printf("thread2pushcomplete");
if(arg)
...{
pthread_exit((void*)2);
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
pthread_exit((void*)2);
}
intmain(void)
...{
interr;
pthread_ttid1,tid2;
void*tret;
err=pthread_create(&tid1,NULL,thr_fn1,(void*)1);
if(err!
=0)
...{
printf("error....");
return-1;
}
err=pthread_create(&tid2,NULL,thr_fn2,(void*)1);
if(err!
=0)
...{
printf("error....");
return-1;
}
err=pthread_join(tid1,&tret);
if(err!
=0)
...{
printf("error....");
return-1;
}
printf("thread1exitcode%d",(int)tret);
err=pthread_join(tid2,&tret);
if(err!
=0)
...{
printf("error....");
return-1;
}gcc-Wall-lpthreadthread_clean.c
printf("thread2exitcode%d",(int)tret);
exit(0);
}