使用多线程的理由:
① 和进程相比,其为一很节俭的多任务操作方式,启动一新进程须为其分配独立地址空间,建立众多数据表来维护代码段、数据段和堆栈段,是一种昂贵多任务工作方式;运行于一进程中多个线程,它们间使用相同地址空间,线程间切换耗时远远小于进程,据统计一进程开销约是一线程开销30倍(fork代码段共享,数据段、堆栈段均不共享,线程间全部共享)
② 线程间方便通信机制,对不同进程,起具有独立数据空间,要进行数据传递只能通过进程间通信方式,这些方式费时不便;线程由于共享数据空间,所以一线程数据可直接为其它线程所用,快捷方便(如定义全局变量,进程中所有线程均可看到)
③ 使多CPU系统更加有效,OS会保证当线程数不大于CPU数时,不同线程运行于不同CPU上
Linux系统下多线程遵循POSIX线程接口,称pthread,编写需使用头文件pthread.h,链接需使用库libpthread.a
——————/创建线程
#include <pthread.h>
int pthread_create(pthread_t * tidp,const pthread_attr_t *attr,void *(*start_rtn)(void),void *arg)
tidp:线程id
attr:线程属性(通常为空)
start_rtn:线程要执行的函数
arg:start_rtn的参数
# gcc filename –lpthread //因gcc编译,默认只用c库
——————/等待线程
int pthread_join(pthread_t tid,void **rval_ptr)
功能:等待指定线程终止(进程等待线程、线程等待线程)
Rval_ptr:参考thread_exit.c
——————/线程退出
如进程中任一线程调用exit或_exit,则整个进程终止,线程正常退出方式有:
(1) 线程从启动例程返回
(2) 线程被另一进程终止
(3) 线程自己调用pthread_exit
void pthread_exit(void * rval_ptr)
Rval_ptr:参考thread_exit.c
——————/线程标识
pthread_t pthread_self(void)
功能:获得当前线程id,参考thread_id.c
——————/线程清除
线程终止有两种情况:正常终止和非正常终止;线程主动调用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)
功能:将清除函数弹出清除栈
参数:是否在弹出清理函数同时执行清理函数,非0执行,0不执行,参考thread_clean.c
——————/
main will block
in thread : 0
in thread : 1
thread exit
in main : 0
in main : 1
——————/传int参
——————/共享数据
——————/thread_exit.c
——————/thread_id.c
thread id=3075590976d
process id in thread=3037
process id in main=3037
——————/thread_clean.c
thread 1 exit code 1
cleanup :thread 2 second handler
cleanup :thread 2 first handler
thread 2 exit code 2
① 和进程相比,其为一很节俭的多任务操作方式,启动一新进程须为其分配独立地址空间,建立众多数据表来维护代码段、数据段和堆栈段,是一种昂贵多任务工作方式;运行于一进程中多个线程,它们间使用相同地址空间,线程间切换耗时远远小于进程,据统计一进程开销约是一线程开销30倍(fork代码段共享,数据段、堆栈段均不共享,线程间全部共享)
② 线程间方便通信机制,对不同进程,起具有独立数据空间,要进行数据传递只能通过进程间通信方式,这些方式费时不便;线程由于共享数据空间,所以一线程数据可直接为其它线程所用,快捷方便(如定义全局变量,进程中所有线程均可看到)
③ 使多CPU系统更加有效,OS会保证当线程数不大于CPU数时,不同线程运行于不同CPU上
Linux系统下多线程遵循POSIX线程接口,称pthread,编写需使用头文件pthread.h,链接需使用库libpthread.a
——————/创建线程
#include <pthread.h>
int pthread_create(pthread_t * tidp,const pthread_attr_t *attr,void *(*start_rtn)(void),void *arg)
tidp:线程id
attr:线程属性(通常为空)
start_rtn:线程要执行的函数
arg:start_rtn的参数
# gcc filename –lpthread //因gcc编译,默认只用c库
——————/等待线程
int pthread_join(pthread_t tid,void **rval_ptr)
功能:等待指定线程终止(进程等待线程、线程等待线程)
Rval_ptr:参考thread_exit.c
——————/线程退出
如进程中任一线程调用exit或_exit,则整个进程终止,线程正常退出方式有:
(1) 线程从启动例程返回
(2) 线程被另一进程终止
(3) 线程自己调用pthread_exit
void pthread_exit(void * rval_ptr)
Rval_ptr:参考thread_exit.c
——————/线程标识
pthread_t pthread_self(void)
功能:获得当前线程id,参考thread_id.c
——————/线程清除
线程终止有两种情况:正常终止和非正常终止;线程主动调用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)
功能:将清除函数弹出清除栈
参数:是否在弹出清理函数同时执行清理函数,非0执行,0不执行,参考thread_clean.c
——————/
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
void *thread(void *str)
{
int i;
for (i = 0; i < 2; ++i)
{
sleep(2);
printf( "in thread : %d\n" , i );
}
return NULL;
}
int main()
{
pthread_t pth;
int i;
pthread_create(&pth, NULL, thread, NULL);
printf("main will block\n");
pthread_join(pth, NULL); //思考去掉该行后执行结果?
printf("thread exit\n");
for (i = 0; i < 2; ++i)
{
sleep(1);
printf( "in main : %d\n" , i );
}
return 0;
}
结果:
main will block
in thread : 0
in thread : 1
thread exit
in main : 0
in main : 1
——————/传int参
void *thread(void *arg)
{
printf("parameter %d\n",*(int*)arg);
return NULL;
}
int main()
{
pthread_t pth;
int test=4;
pthread_create(&pth, NULL, thread, (void*)&test);
sleep(1);
return 0;
}
结果:parameter 4
——————/共享数据
int test=4;
void *thread(void *arg)
{
printf("a= %d\n",test++);
return NULL;
}
int main()
{
pthread_t pth;
pthread_create(&pth, NULL, thread, NULL);
sleep(1);
printf("a= %d\n",test);
return 0;
}
结果:a= 4 a= 5
——————/thread_exit.c
void *thread(void *arg)
{
pthread_exit((void*)1);
return (void*)2;
}
int main()
{
pthread_t pth;
void *ret;
pthread_create(&pth, NULL, thread, NULL);
pthread_join(pth,&ret);
printf("return= %d\n",(int)ret);
return 0;
}
结果:1
——————/thread_id.c
void *thread(void *arg)
{
printf("thread id=%ud\n",(unsigned int)pthread_self());
printf("process id in thread=%d\n",getpid());
return NULL;
}
int main()
{
pthread_t pth;
pthread_create(&pth, NULL, thread, NULL);
sleep(1);
printf("process id in main=%d\n",getpid());
return 0;
}
结果:
thread id=3075590976d
process id in thread=3037
process id in main=3037
——————/thread_clean.c
void *clean(void *arg)
{
printf("cleanup :%s\n",(char *)arg);
return NULL;
}
void *thr_fn1(void *arg)
{
pthread_cleanup_push( (void*)clean,"thread 1 first handler");
pthread_cleanup_push( (void*)clean,"thread 1 second hadler");
if(arg)
{
return (void *)1;
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
return (void *)1;
}
void *thr_fn2(void *arg)
{
pthread_cleanup_push( (void*)clean,"thread 2 first handler");
pthread_cleanup_push( (void*)clean,"thread 2 second handler");
if(arg)
{
pthread_exit((void *)2);
}
pthread_cleanup_pop(0);
pthread_cleanup_pop(0);
pthread_exit((void *)2);
}
int main(void)
{
pthread_t tid1,tid2;
void *tret;
pthread_create(&tid1,NULL,thr_fn1,(void *)1);
pthread_create(&tid2,NULL,thr_fn2,(void *)1);
pthread_join(tid1,&tret);
printf("thread 1 exit code %d \n",(int)tret);
pthread_join(tid2,&tret);
printf("thread 2 exit code %d \n",(int)tret);
return 0;
}
结果:
thread 1 exit code 1
cleanup :thread 2 second handler
cleanup :thread 2 first handler
thread 2 exit code 2