全部博文(298)
分类: LINUX
2011-04-04 16:32:08
初等线程相关
注意多线程编译时必须加上-lpthread选项,否则显示线程函数及其相关定义为未定义。
比如:
gcc filename.c -o filename -lpthread就行了#include
1. int pthread_equal(pthread_t tid1, pthread_t tid2)
返回值:相等返回非0值, 不等返回0
2. pthread_t pthread_self(void)
返回值:调用线程的线程ID
3. int pthread_create(pthread_t *restrict tidp,
const pthread_attr_t *restrict attr,
void *(*start_rtn)(void), void *restrict arg);
返回值:成功返回0, 否则返回错误编号
restrict attr = NULL 取默认属性
线程简单属性相关:
4. int pthread_atrr_init(pthread_attr_t *attr)
5. int pthread_atrr_destroy(pthread_attr_t *attr)
返回值:成功返回0, 否则返回错误编号
线程简单属性表:(每中系统支持值请查《unix高级编程》中文版P314)
detachstate 线程的分离状态
guardsize 线程栈末尾的警戒缓冲区的大小(字节)
stackaddr 线程栈的最低地址
stacksize 线程栈的大小(字节)
线程终止相关:
6. void pthread_exit(void *rval_ptr) rval_ptr参数是其返回值
7. int pthread_join(pthread_t thread, void **rval_ptr);
返回值:成功返回0, 否则返回错误编号
8. int pthread_cancel(pthread_t tid)
返回值:成功返回0,错误返回错误编号
9. void pthread_cleanup_push(void (*rtn)(void *), void *arg)
10.void pthread_cleanup_pop(int execute)
清理函数的顺序由pthread_cleanup_push函数注册顺序决定的,是逆序使用的,execute参数表示执行到pthread_cleanup_pop()时是否在弹出清理函数的同时执行该函数,为0表示不执行,非0为执行;这个参数并不影响异常终止时清理函数的执行。
11. int pthread_detach(pthread_t tid)
返回值:成功返回0, 否则返回错误编号
关于pthread_exit和return
理论上说,pthread_exit()和线程宿体函数退出的功能是相同的,函数结束时会在内部自动调用pthread_exit()来清理线程相关的资源。但实际上二者由于编译器的处理有很大的不同。
在进程主函数(main())中调用pthread_exit(),只会使主函数所在的线程(可以说是进程的主线程)退出;而如果是return,编译器将使其调用进程退出的代码(如_exit()),从而导致进程及其所有线程结束运行。
其次,在线程宿主函数中主动调用return,如果return语句包含在pthread_cleanup_push()/pthread_cleanup_pop()对中,则不会引起清理函数的执行,反而会导致segment fault。
例子程序1:
#include
#include "apue.h"
#include
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);
// pthread_exit((void*)0);
}
int
main(void)
{
int err;
err = pthread_create(&ntid, NULL, thr_fn, NULL);
if(err != 0)
{
printf("can't create new thread : %s\n",
strerror(err));
exit(-1);
}
printids("nain thread: ");
sleep(1);
return 0;
}
我电脑上运行结果:
new thread : pid 15265 tid 1082334400 (0x40831cc0)
nain thread: pid 15265 tid 1073943168 (0x40031280)
例子程序2:
#include "apue.h"
#include
struct foo{
int a, b, c, d;
};
void
printfoo(const char *s,const struct foo *fp)
{
// printf("%s\n", s);
printf(s);
printf(" struct at 0x%x\n", (unsigned int)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("thread 1 :\n", &foo);
pthread_exit((void *)&foo);
}
void *
thr_fn2(void *arg)
{
printf("thread 2: ID is %d \n", pthread_self());
return ((void *)0);
}
void
err_quit1(const char *s, const char *s1)
{
printf("%s %s", s, s1);
exit(-1);
}
int
main(void)
{
int err;
pthread_t tid1, tid2;
struct foo *fp;
err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if(err != 0)
err_quit1("can't create new thread 1:", strerror(err));
err = pthread_join(tid1, (void *)&fp);
if(err != 0)
err_quit1("join error :", strerror(err));
sleep(1);
printf("parent starting second thread \n");
err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if(err != 0)
err_quit1("can't create new thread 2:", strerror(err));
sleep(1);
printfoo("parent : \n", fp);
return 0;
}
我电脑上运行结果:
thread 1 :
struct at 0x4083189c
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4
parent starting second thread
thread 2: ID is 1082334400
parent :
struct at 0x4083189c
foo.a = 1108543764
foo.b = 0
foo.c = 1082333364
foo.d = 1108426211
注意:由于新建的线程是继承了主线程的堆栈,屏蔽字等信息的,所以在建立第二线程的时候可能已经把第一线程的数据给覆盖了,为了解决这一问题,可以采用全局变量和动态分配的方式。
例子程序3:
*********************************************************************
#include
#include
#include
void
cleanup(void *arg)
{
printf("cleanup: %s\n",(char *)arg);/*注意void *的用法*/
}
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) // Makes a call to pthread_exit
{
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);
}
void *
thr_fn3(void *arg) // Makes a call to pthread_cleanup_pop with a
//nonzero execute argument
{
printf("thread 3 start\n");
pthread_cleanup_push(cleanup,"thread 3 first handler");
pthread_cleanup_push(cleanup,"thread 3 second handler");
printf("thread 3 push complete\n");
pthread_cleanup_pop(1);//非0参数
pthread_cleanup_pop(1);
return 0;
}
void *
thr_fn4(void *arg) // Responds to a cancellation request
{
printf("thread 4 start\n");
pthread_cleanup_push(cleanup,"thread 4 first handler");
pthread_cleanup_push(cleanup,"thread 4 second handler");
printf("thread 4 push complete\n");
sleep(2);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return 0;
}
int main()
{
int err;
pthread_t tid1,tid2,tid3,tid4;
void *tret;
err=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(err!=0)
printf("can't create thread 1:%s\n",strerror(err));
err=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(err!=0)
printf("can't create thread 2:%s\n",strerror(err));
err=pthread_create(&tid3,NULL,thr_fn3,(void *)1);
if(err!=0)
printf("can't create thread 3:%s\n",strerror(err));
err=pthread_create(&tid4,NULL,thr_fn4,(void *)1);
if(err!=0)
printf("can't create thread 4:%s\n",strerror(err));
err=pthread_cancel(tid4);
if(err!=0)
printf("can't cancel with thread 4: %s\n",strerror(err));
err=pthread_join(tid1,&tret);
if(err!=0)
printf("can't join with thread 1: %s\n",strerror(err));
printf("thread 1 exit code %d\n",(int)tret);
err=pthread_join(tid2,&tret);
if(err!=0)
printf("can't join with thread 2:%s\n",strerror(err));
printf("thread 2 exit code %d\n",(int)tret);
err=pthread_join(tid3,&tret);
if(err!=0)
printf("can't join with thread 3:%s\n",strerror(err));
printf("thread 3 exit code %d\n",(int)tret);
err=pthread_join(tid4,&tret);
if(err!=0)
printf("can't join with thread 4:%s\n",strerror(err));
printf("thread 4 exit code %d\n",(int)tret);
exit(0);
}
结果:
thread 1 start
thread 1 push complete
thread 2 start
thread 2 push complete
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread 3 start
thread 3 push complete
cleanup: thread 3 second handler
cleanup: thread 3 first handler
thread 4 start
thread 4 push complete
thread 1 exit code 1
thread 2 exit code 2
thread 3 exit code 0
cleanup: thread 4 second handler
cleanup: thread 4 first handler
thread 4 exit code -1
*********************************************************************
从输出结果可以看出,如果线程是从它的启动例程中返回而终止的话并且没有调用非0参数的pthread_cleanup_pop就不会调用其清理函数,还有注意的是我们企图取消线程4,后面调用pthread_join(tid4,&tret);出错,导致调用了清理函数。这一点对比与例子程序4
例子程序4:
#include
#include
#include
void
cleanup(void *arg)
{
printf("cleanup: %s\n",(char *)arg);/*注意void *的用法*/
}
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) // Makes a call to pthread_exit
{
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);
}
void *
thr_fn3(void *arg) // Makes a call to pthread_cleanup_pop with a
//nonzero execute argument
{
printf("thread 3 start\n");
pthread_cleanup_push(cleanup,"thread 3 first handler");
pthread_cleanup_push(cleanup,"thread 3 second handler");
printf("thread 3 push complete\n");
pthread_cleanup_pop(1);//非0参数
pthread_cleanup_pop(1);
return 0;
}
void *
thr_fn4(void *arg) // Responds to a cancellation request
{
printf("thread 4 start\n");
pthread_cleanup_push(cleanup,"thread 4 first handler");
pthread_cleanup_push(cleanup,"thread 4 second handler");
printf("thread 4 push complete\n");
sleep(2);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return 0;
}
int main()
{
int err;
pthread_t tid1,tid2,tid3,tid4;
void *tret;
err=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(err!=0)
printf("can't create thread 1:%s\n",strerror(err));
err=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(err!=0)
printf("can't create thread 2:%s\n",strerror(err));
err=pthread_create(&tid3,NULL,thr_fn3,(void *)1);
if(err!=0)
printf("can't create thread 3:%s\n",strerror(err));
err=pthread_create(&tid4,NULL,thr_fn4,(void *)1);
if(err!=0)
printf("can't create thread 4:%s\n",strerror(err));
/* err=pthread_cancel(tid4);
if(err!=0)
printf("can't cancel with thread 4: %s\n",strerror(err));
*/ err=pthread_join(tid1,&tret);
if(err!=0)
printf("can't join with thread 1: %s\n",strerror(err));
printf("thread 1 exit code %d\n",(int)tret);
err=pthread_join(tid2,&tret);
if(err!=0)
printf("can't join with thread 2:%s\n",strerror(err));
printf("thread 2 exit code %d\n",(int)tret);
err=pthread_join(tid3,&tret);
if(err!=0)
printf("can't join with thread 3:%s\n",strerror(err));
printf("thread 3 exit code %d\n",(int)tret);
err=pthread_join(tid4,&tret);
if(err!=0)
printf("can't join with thread 4:%s\n",strerror(err));
printf("thread 4 exit code %d\n",(int)tret);
exit(0);
}
结果:
thread 1 start
thread 1 push complete
thread 2 start
thread 2 push complete
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread 3 start
thread 3 push complete
cleanup: thread 3 second handler
cleanup: thread 3 first handler
thread 4 start
thread 4 push complete
thread 1 exit code 1
thread 2 exit code 2
thread 3 exit code 0
thread 4 exit code 0
例子程序5:
注意参数void*和void **的用法
#include "apue.h"
#include
void
cleanup(void *arg)
{
printf((char *)arg);
printf("cleanup : %s\n", (char *)arg);
}
void *
thr_fn1(void *arg)
{
//printf("thread 1 start :%d\n", (int)(*arg));/*为什么会有错?*/
printf("thread 1 start :%d\n", (int)arg);
printf("thread 1 start :%d\n", (int *)arg);
//printf("thread 1 start :%d\n", *(int *)arg);/*??*/
pthread_cleanup_push(cleanup, "thread 1 first handler");
pthread_cleanup_push(cleanup, "thread 1 second handler");
printf("thread 1 push complete\n");
if(arg)
//pthread_exit((void *)1);
return ((void *)1);
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
//pthread_exit((void *)1);
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(void)
{
int err;
pthread_t tid1, tid2;
void *tret;
err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);
err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);
err = pthread_join(tid1, &tret);
printf("thread 1 exit code %d\n", (int)tret);/*??*/
err = pthread_join(tid2, &tret);
printf("thread 2 exit code %d\n", (int)tret);
//return 0;
exit(0);
}
结果:
thread 1 start :1
thread 1 start :1
thread 1 push complete
thread 2 start
thread 2 push complete
thread 2 second handlercleanup : thread 2 second handler
thread 2 first handlercleanup : thread 2 first handler
thread 1 exit code 1
thread 2 exit code 2