分类: LINUX
2010-05-05 21:02:00
1线程创建
函数原型:
|
返回值:若是成功建立线程返回0,否则返回错误的编号
形式参数:
pthread_t *restrict tidp 要创建的线程的线程id指针
const pthread_attr_t *restrict attr 创建线程时的线程属性
void* (start_rtn)(void) 返回值是void类型的指针函数
vodi *restrict arg start_rtn的行参
例题1:
功能:建立一个新的线程
程序名称: pthread_test.c
|
编译方法:
因为pthread的库不是系统的库,所以在进行编译的时候要加上-lpthread,否则编译不过,会出现下面错误
现在我们能建立了一个线程了,我们可以从函数的原型看到,在创建线程的时候,是可以在对我们的函数进行传递参数,在pthread_create的第四个行参。我们看一下例题2~3.
例题2
功能:向新的线程传递整形值
程序名称:pthread_int.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *create(void *arg)
...{
int *num;
num=(int *)arg;
printf("create parameter is %d ",*num);
return (void *)0;
}
int main(int argc ,char *argv[])
...{
pthread_t tidp;
int error;
int test=4;
int *attr=&test;
error=pthread_create(&tidp,NULL,create,(void *)attr);
if(error!=0)
...{
printf("pthread_create is created is not created ... ");
return -1;
}
sleep(1);
printf("pthread_create is created is created ... ");
return 0;
}
编译方法:
执行结果:
例题总结:
可以看出来,我们在main函数中传递的整行指针,传递到我们新建的线程函数中。
在上面的例子可以看出来我们向新的线程传入了另一个线程的int数据,线程之间还可以传递字符串或是更复杂的数据结构。
例题3:
程序功能:向新建的线程传递字符串
程序名称:thread_char.c
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
void *create(void *arg)
...{
char *name;
name=(char *)arg;
printf("arg is %s ",name);
return (void *)0;
}
int main(int argc,char *argv[])
...{
char *a="wang";
int error;
pthread_t tidp;
error=pthread_create(&tidp,NULL,create,(void *)a);
if(error!=0)
...{
printf("pthread is not created ");
return -1;
}
sleep(1);
printf("pthread is created... ");
return 0;
}
编译方法:
执行结果:
例题总结:
可以看出来main函数中的字符串传入了新建里的线程中。
例题4
程序名称:thread_struct.c
|
执行结果:
线程包含了标识进程内执行环境必须的信息。他集成了进程中的所有信息都是对线程进行共享的,包括文本程序、程序的全局内存和堆内存、栈以及文件描述符。
例题5
程序目的:验证新建立的线程可以共享进程中的数据
程序名称:thread_share.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
static int a=4;
void *create(void *arg)
...{
printf("new pthread ... ");
printf("a==%d ",a);
return (void *)0;
}
int main(int argc,char *argv[])
...{
pthread_t tidp;
int error;
a=5;
error=pthread_create(&tidp,NULL,create,NULL);
if(error!=0)
...{
printf("new thread is not create ... ");
return -1;
}
sleep(1);
printf("new thread is created ... ");
return 0;
}
编译方法:
执行结果:
例题总结:可以看出来,我们在主线程更改了我们的全局变量a的值的时候,我们新建立的线程则打印出来了改变的值,可以看出可以访问线程所在进程中的数据信息。
如果进程中任何一个线程中调用exit,_Exit,或者是_exit,那么整个进程就会终止,与此类似,如果信号的默认的动作是终止进程,那么,把该信号发送到线程会终止进程。
线程的正常退出的方式:
(1) 线程只是从启动例程中返回,返回值是线程中的退出码
(2) 线程可以被另一个进程进行终止
(3) 线程自己调用pthread_exit函数
两个重要的函数原型:
#include <pthread.h>
void pthread_exit(void *rval_ptr);
/*rval_ptr 线程退出返回的指针*/
int pthread_join(pthread_t thread,void **rval_ptr);
/*成功结束进程为0,否则为错误编码*/
例题6
程序目的:线程正常退出,接受线程退出的返回码
程序名称:exit_return.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *create(void *arg)
...{
printf("new thread is created ... ");
return (void *)2;
}
int main(int argc,char *argv[])
...{
pthread_t tid;
int error;
void *temp;
error=pthread_create(&tid,NULL,create,NULL);
if(error!=0)
...{
printf("thread is not created ... ");
return -1;
}
error=pthread_join(tid,&temp);
if(error!=0)
...{
printf("thread is not exit ... ");
return -2;
}
printf("thread is exit code %d ",(int )temp);
sleep(1);
printf("thread is created... ");
return 0;
}
编译方法:
执行结果:
线程退出不仅仅可以返回线程的int数值,还可以返回一个复杂的数据结构
例题7
程序目的:线程结束返回一个复杂的数据结构
程序名称:exit_thread.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
struct test
...{
int a;
char *b;
};
struct test temp=
...{
.a =4,
.b ="wang"
};
void *create(void *arg)
...{
printf("new thread ... ");
return (void *)&temp;
}
int main(int argc,char *argv[])
...{
int error;
pthread_t tid;
struct test *c;
error=pthread_create(&tid,NULL,create,NULL);
if(error!=0)
...{
printf("new thread is not created ... ");
return -1;
}
printf("main ... ");
error=pthread_join(tid,(void *)&c);
if(error!=0)
...{
printf("new thread is not exit ... ");
return -2;
}
printf("c->a ==%d ",c->a);
printf("c->b ==%s ",c->b);
sleep(1);
return 0;
}
编译方法:
执行结果:
例题总结:一定要记得返回的数据结构要是在这个数据要返回的结构没有释放的时候应用,如果数据结构已经发生变化,那返回的就不会是我们所需要的,而是藏数据阿。
3、线程标识
函数原型:
#include <pthread.h>
pthread_t pthread_self(void);
例题8
程序目的:实现在新建立的线程中打印该线程的id和进程id
程序名称:thread_self.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h> /**//*getpid()*/
void *create(void *arg)
...{
printf("new thread .... ");
printf("thread_tid==%u ",(unsigned int)pthread_self());
printf("thread pid is %d ",getpid());
return (void *)0;
}
int main(int argc,char *argv[])
...{
pthread_t tid;
int error;
printf("Main thread is starting ... ");
error=pthread_create(&tid,NULL,create,NULL);
if(error!=0)
...{
printf("thread is not created ... ");
return -1;
}
printf("main pid is %d ",getpid());
sleep(1);
return 0;
}
编译方法:
执行结果:
4、 线程的处理程序
函数原型:
#include <pthread.h>
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
函数rtn是清理函数,arg是调用参数
void pthread_cleanup_pop(int execute);
在前面讲过线程的终止方式,是正常终止还是非正常终止,都会存在一个资源释放的问题,在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
编译方法:
执行结果:
|
执行结果:
thread 1 push complete
thread 1 exit code 1
thread 2 start
thread 2 push complete
cleanup :thread 2 second handler
cleanup :thread 2 first handler
thread 2 exit code 2