1、非常‘节俭’的多任务操作方式,在Linux系统中,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表类维护它的代码段、堆栈段和数据段,只是一种“昂贵”的多任务工作方式
运行一个进程中的多个线程,他们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间,约为进程开销的1/30
2、线程间方便的通信机制,对不同进程来说它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,线程不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其他线程所用,这不仅快捷,而且方便
3、使用CPU系统更加有效,操作系统会保证当线程数目不大于CPU数目时,不同的线程运行于不同的CPU上
4、改善程序结构,一个即长又复杂的进程可以考虑分为多个进程,成为几个独立或半独立的运行部分,这样的程序会李雨理解和修改
Linux系统下的多线程遵循POSIX线程接口,成为pthread。编写Linux下的多线程程序,需要使用头文件pehread.h,连接时需要使用库libptread.h
int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict_arg);
tidp:线程ID
restrict_attr:线程属性(通常为空)
start_rtn:线程要执行的函数
restrict_arg:start_rtn的参数
因为pthread的库不是linux系统的库,所以在编译时要加上-lpthread
gcc filename -lpthread
#include
#include
void *myThread1(void)
{
int i;
printf("OK\n");
for(i=0;i<100;i++)
{
printf("This is the 1st pthread,created by gyy.\n");
sleep(1);
}
}
void *myThread2(void)
{
int i;
for(i=0;i<100;i++)
{
printf("This is the 2nd pthread,created by gyy.\n");
sleep(1);
}
}
int main()
{
int i=0,ret=0;
pthread_t id1,id2;
printf("OK1\n");
ret=pthread_create(&id1,NULL,(void *)myThread1,NULL);
if(ret)
{
printf("Create pthread1 error!\n");
return 1;
}
ret=pthread_create(&id2,NULL,(void *)myThread2,NULL);
if(ret)
{
printf("Create pthread1 error!\n");
return 1;
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
return 0;
}
运行结果
[gyy@localhost thread]$ gcc thread_create.c -lpthread -o thread_create
[gyy@localhost thread]$ ./thread_create
This is the 1st pthread,created by gyy.
This is the 2nd pthread,created by gyy.
This is the 1st pthread,created by gyy.
This is the 2nd pthread,created by gyy.
This is the 1st pthread,created by gyy.
This is the 2nd pthread,created by gyy.
This is the 1st pthread,created by gyy.
This is the 2nd pthread,created by gyy.
This is the 1st pthread,created by gyy.
This is the 2nd pthread,created by gyy.
This is the 1st pthread,created by gyy.
向线程传递参数例程
#include
#include
#include
void *create(void *arg)
{
int *num;
num=(int *)arg;
printf("create parameter is %d\n",*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)
{
printf("pthread_create is not created...\n");
return -1;
}
sleep(1);
printf("p_thread_create is created...\n");
return 0;
}
运行结果
[gyy@localhost thread]$ gcc thread_int.c -lpthread -o thread_int
[gyy@localhost thread]$ ./thread_int
create parameter is 4
p_thread_create is created...
代码分析:展示如何向线程传递整型参数,先得到参数的地址,然后转为(void *)型,然后传递给thread_create,参数的类型的定死的,必须为指针
线程间资源共享例程1
#include
#include
#include
int a=1;
void *create(void *arg)
{
printf("new pthread...\n");
printf("in new pthread a= %d\n",a);
a++;
return (void *) 0;
}
int main(int argc,char *argv[])
{
pthread_t tidp;
int error;
printf("in main 1 a=%d\n",a);
error=pthread_create(&tidp,NULL,create,NULL);
if(error)
{
printf("pthread_create is not created...\n");
return -1;
}
sleep(1);
printf("in main 2 a=%d\n",a);
return 0;
}
运行结果
[gyy@localhost thread]$ gcc thread_share.c -lpthread -o thread_share
[gyy@localhost thread]$ ./thread_share
in main 1 a=1
new pthread...
in new pthread a= 1
in main 2 a=2
代码分析:线程使用了全局变量并将a自增
线程间资源共享例程2
#include
#include
#include
int a=1;
void *create(void *arg)
{
printf("new pthread...\n");
printf("in new pthread a= %d\n",a);
a++;
return (void *) 0;
}
int main(int argc,char *argv[])
{
pthread_t tidp;
int error;
int a=4;
printf("in main 1 a=%d\n",a);
error=pthread_create(&tidp,NULL,create,NULL);
if(error)
{
printf("pthread_create is not created...\n");
return -1;
}
sleep(1);
printf("in main 2 a=%d\n",a);
return 0;
}
运行结果
[gyy@localhost thread]$ gcc thread_share2.c -lpthread -o thread_share2
[gyy@localhost thread]$ ./thread_share2
in main 1 a=4
new pthread...
in new pthread a= 1
in main 2 a=4
代码分析:main中的代码使用局部变量,线程中的代码使用全局变量
在线程中应当是优先使用数据段的变量(在堆中的),局部变量存放在栈中
如果任何一个线程中调用exit或_exit,那么整个进程都会终止,线程正常的退出方式有:
1、线程从启动例程中返回
2、线程可以被另一个进程终止
3、线程自己调用pthread_exit函数
void pthread_exit(void *rval_ptr)
终止调用的线程
rval_ptr:线程退出返回值的指针
线程使用终止例程
#include
#include
#include
void *create(void *arg)
{
printf("new thread is create...\n");
return (void *) 8;
}
int main(int argc,char *crgv[])
{
pthread_t tid;
int error;
void *temp;
error=pthread_create(&tid,NULL,create,NULL);
printf("main thread!\n");
if(error)
{
printf("thread is not create...\n");
return -1;
}
error=pthread_join(tid,&temp);
if(error)
{
printf("thread is not exit...\n");
return -2;
}
printf("thread's exit code %d \n",(int)temp);
return 0;
}
运行结果
[gyy@localhost thread]$ ./thread_exit
main thread!
new thread is create...
thread's exit code 8
代码分析:线程从启动程序中返回
线程调用pthread_exit终止例程
#include
#include
#include
void *create(void *arg)
{
int ret=10;
printf("new thread is create...\n");
pthread_exit((void *)ret);
}
int main(int argc,char *crgv[])
{
pthread_t tid;
int error;
void *temp;
error=pthread_create(&tid,NULL,create,NULL);
printf("main thread!\n");
if(error)
{
printf("thread is not create...\n");
return -1;
}
error=pthread_join(tid,&temp);
if(error)
{
printf("thread is not exit...\n");
return -2;
}
printf("thread's exit code %d \n",(int)temp);
return 0;
}
运行结果
[gyy@localhost thread]$ ./thread_exit
main thread!
new thread is create...
thread's exit code 10
代码分析:线程调用pthread_exit函数退出
int pthread_join(pthread_t tid,void *rval_ptr);
阻塞调用线程,直到指定的线程终止
tid:等待推出的线程ID
rval_ptr:线程退出的返回值的指针
#include
#include
#include
void *thread(void)
{
int i;
for(i=0;i<5;i++)
{
sleep(2);
printf("This is in the new thread: %d\n",i);
}
return NULL;
}
int main()
{
pthread_t tid;
int i;
int ret=pthread_create(&tid,NULL,thread,NULL);
pthread_join(tid,NULL);
printf("in the main\n");
for(i=0;i<5;++i)
{
sleep(1);
printf("This is in the main:%d\n",i);
}
return 0;
}
运行结果
[gyy@localhost thread]$ gcc thread_join.c -lpthread -o thread_join
[gyy@localhost thread]$ ./thread_join
This is in the new thread: 0
This is in the new thread: 1
This is in the new thread: 2
This is in the new thread: 3
This is in the new thread: 4
in the main
This is in the main:0
This is in the main:1
This is in the main:2
This is in the main:3
This is in the main:4
代码分析:调用pthread_join函数后阻塞调用线程main,直到线程thread执行完毕后main线程才继续执行
注释掉pthread_join后运行结果
[gyy@localhost thread]$ ./thread_join
in the main
This is in the main:0
This is in the new thread: 0
This is in the main:1
This is in the main:2
This is in the new thread: 1
This is in the main:3
This is in the main:4
代码分析:同时执行,创建线程后线程处于就绪态,在执行到sleep时才会发生调度,当进程退出时它当中的所有线程都退出
当注释掉main中的sleep运行结果
[gyy@localhost thread]$ ./thread_join
in the main
This is in the main:0
This is in the main:1
This is in the main:2
This is in the main:3
This is in the main:4
代码分析:不会发生调度
pthread_t pthread_self(void)
获取调用线程的thread identifier
#include
#include
#include
void *create(void *arg)
{
printf("New thread...\n");
printf("This thread's id is %u \n",(unsigned int)pthread_self());
printf("The process pid is %d\n",getpid());
return (void *)0;
}
int main()
{
pthread_t tid;
int error;
printf("Main thread is starting...\n");
error=pthread_create(&tid,NULL,create,NULL);
if(error)
{
printf("thread is not create...\n");
return -1;
}
printf("The main thread's id is %u \n",(unsigned int)pthread_self());
printf("The main process pid is %d\n",getpid());
sleep(1);
return 0;
}
运行结果
[gyy@localhost thread]$ ./thread_id
Main thread is starting...
The main thread's id is 2694051648
The main process pid is 7538
New thread...
This thread's id is 2685671168
The process pid is 7538
线程终止有两种情况:正常终止和非正常终止,正常终止就是调用pthread_exit或者return;而非正常终止是线程在其他线程的干预下,或者由于自身运行出错(比如访问非法地址)而退出,这种退出方式是不可预见的
不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,要确保线程终止时能释放自己的资源
从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中的终止动作(包括调用pthread_exit()和异常终止,不包括return)都将执行pthread_cleanup_push()所指定的清理函数
可以使用这俩函数将某段代码保护起来
void pthread_cleanup_push (void(*rtn)(void *),void *arg)
将清除函数压入清除栈
rtn:清除函数
arg:清除函数的参数
void pthread_cleanup_pop (int execute)
将清除函数弹出清除栈
execute:是否在弹出清除函数的同时执行该函数,非0执行,0不执行
#include
#include
#include
#include
void clean(void *arg)
{
printf("cleanup: %s \n",(char *)arg);
return (void *)0;
}
void *thr_fn1(void *arg)
{
printf("thread 1 start... \n");
pthread_cleanup_push((void *)clean,"thread 1 first handler");
pthread_cleanup_push((void *)clean,"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)
{
printf("thread 2 start... \n");
pthread_cleanup_push((void *)clean,"thread 2 first handler");
pthread_cleanup_push((void *)clean,"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 error;
pthread_t tid1,tid2;
void *tret;
error=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_join(tid1,&tret);
if(error)
{
printf("thread1 join error...\n");
return -1;
}
printf("thread1 exit code %d\n",(int)tret);
error=pthread_join(tid2,&tret);
if(error)
{
printf("thread2 join error...\n");
return -1;
}
printf("thread2 exit code %d\n",(int)tret);
}
运行结果
[gyy@localhost thread]$ ./thread_clean
thread 2 start...
thread 1 start...
thread 1 push complete
thread 2 push complete
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread1 exit code 1
thread2 exit code 2
代码分析:thread1是用return终止线程,所以说不会调用clean,thread使用exit终止,所以说会调用clean,而存储方式是栈,所以second handler先被打印(它后被压入,后入先出)
都注释掉pop前面的终止(即让程序运行到pop)例程
#include
#include
#include
#include
void clean(void *arg)
{
printf("cleanup: %s \n",(char *)arg);
return (void *)0;
}
void *thr_fn1(void *arg)
{
printf("thread 1 start... \n");
pthread_cleanup_push((void *)clean,"thread 1 first handler");
pthread_cleanup_push((void *)clean,"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)
{
printf("thread 2 start... \n");
pthread_cleanup_push((void *)clean,"thread 2 first handler");
pthread_cleanup_push((void *)clean,"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 error;
pthread_t tid1,tid2;
void *tret;
error=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_join(tid1,&tret);
if(error)
{
printf("thread1 join error...\n");
return -1;
}
printf("thread1 exit code %d\n",(int)tret);
error=pthread_join(tid2,&tret);
if(error)
{
printf("thread2 join error...\n");
return -1;
}
printf("thread2 exit code %d\n",(int)tret);
}
运行结果
[gyy@localhost thread]$ ./thread_clean2
thread 2 start...
thread 2 push complete
thread 1 start...
thread 1 push complete
thread1 exit code 1
thread2 exit code 2
代码分析:pop的参数为0,运行到这里弹出clean的时候不会执行
将pop的参数都改为1例程
#include
#include
#include
#include
void clean(void *arg)
{
printf("cleanup: %s \n",(char *)arg);
return (void *)0;
}
void *thr_fn1(void *arg)
{
printf("thread 1 start... \n");
pthread_cleanup_push((void *)clean,"thread 1 first handler");
pthread_cleanup_push((void *)clean,"thread 1 second handler");
printf("thread 1 push complete\n");
// if(arg)
// {
// return ((void *)1);
// }
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
return (void *)1;
}
void *thr_fn2(void *arg)
{
printf("thread 2 start... \n");
pthread_cleanup_push((void *)clean,"thread 2 first handler");
pthread_cleanup_push((void *)clean,"thread 2 second handler");
printf("thread 2 push complete\n");
// if(arg)
// {
// pthread_exit((void *)2);
// }
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
pthread_exit((void *)2);
}
int main(void)
{
int error;
pthread_t tid1,tid2;
void *tret;
error=pthread_create(&tid1,NULL,thr_fn1,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_create(&tid2,NULL,thr_fn2,(void *)1);
if(error!=0)
{
printf("threat1 create error...\n");
return -1;
}
error=pthread_join(tid1,&tret);
if(error)
{
printf("thread1 join error...\n");
return -1;
}
printf("thread1 exit code %d\n",(int)tret);
error=pthread_join(tid2,&tret);
if(error)
{
printf("thread2 join error...\n");
return -1;
}
printf("thread2 exit code %d\n",(int)tret);
}
运行结果
[gyy@localhost thread]$ ./thread_clean2
thread 2 start...
thread 2 push complete
cleanup: thread 2 second handler
cleanup: thread 2 first handler
thread 1 start...
thread 1 push complete
cleanup: thread 1 second handler
cleanup: thread 1 first handler
thread1 exit code 1
thread2 exit code 2
代码分析:pop的参数为1,运行到这里弹出clean并执行