-
一、线程基本概念(pthread 线程)
共同点:都可并发
优点: 比多进程节省资源,可以共享变量。
概念: 线程是轻量级进程,一般是一个进程中的多个任务。
进程是系统中最小的资源分配单位.
线程是系统中最小的执行单位。
特征:
1、共享资源(线程共享,进程不共享)
2、效率高 30%(并发度更高,调度比进程更快)
3、三方库: pthread clone posix (一种协议,便于移植)3.1 编写代码头文件: pthread.h
3.2 编译代码加载库: -lpthread library
libpthread.so
gcc 1.c -lpthread
缺点:
1,线程和进程相比,稳定性,稍微差些(一个线程异常,整个线程结束)
2,线程的调试gdb,相对麻烦些。
线程与进程区别:
资源:
线程比进程多了共享资源(除了栈区,剩下堆区等都共享)。 IPC
线程又具有部分私有资源(栈区)。
进程间只有私有资源没有共享资源。
空间:
进程空间独立,不能直接通信。
线程可以共享空间,可以直接通信。
二、多线程编写步骤
2.1 设计框架
创建多线程 ----->线程空间操作 ------>线程资源回收
(第一个线程叫主线程,线程平级关系)
报错:errno strerror(errno) / perror();
2.2 创建多线程
int pthread_create( pthread_t *thread, const pthread_attr_t *attr, // 线程号 属性(若为null,默认属性) void *(*start_routine) (void *), void *arg); // 函数指针,写函数名(回调函数),线程创建成功 参数(可能需要外部传参,若不 需要,则为null)
功能:该函数可以创建指定的一个线程。
参数:thread 线程id,需要实现定义并由该函数返回。
attr 线程属性,一般是NULL,表示默认属性。
start_routine 指向指针函数的函数指针。
本质上是一个函数的名称即可。称回调函数,是线程的执行空间。
arg 回调函数的参数,即参数3的指针函数参数。
返回值:成功 0
失败 错误码
注意: 一次pthread_create执行只能创建一个线程。
每个进程至少有一个线程称为主线程。
主线程退出则所有创建的子线程都退出。
主线程必须有子线程同时运行才算多线程程序。
线程id是线程的唯一标识,是CPU维护的一组数字。
pstree 查看系统中多线程的对应关系。
多个子线程可以执行同一回调函数。
ps -eLf 查看线程相关信息Low Weigth Process
ps -eLo pid,ppid,lwp,stat,comm
2.3 获取线程号
pthread_t pthread_self(void);
unsigned long int; %lu
功能:获取当前线程的线程id
参数:无
返回值:成功 返回当前线程的线程id
失败 -1;
syscall(SYS_gettid);
这个方法重启后失效
alias gcc='gcc -g -pthread '
unalias gcc永久起作用
cd ~ //家目录
vim .bashrc
alias gcc='gcc -g -pthread ' :wqsource .bashrc 生效
2.4 线程的退出
1: 自行退出 ==》自杀 ==》子线程自己退出
exit(1);
void pthread_exit(void *retval);
exit return p;
功能:子线程自行退出
参数: retval 线程退出时候的返回状态,临死遗言。
返回值:无th
{
int a =10;pthread_exit(&a);
}
join(,&ret)
2: 强制退出 ==》他杀 ==》主线程结束子线程
int pthread_cancel(pthread_t thread);
功能:请求结束一个线程
参数:thread 请求结束一个线程tid
返回值:成功 0
失败 -1;
三、线程的回收
3.1 线程的回收机制
不同与进程没有孤儿线程和僵尸线程。
主线程结束任意生成的子线程都会结束。
子线程的结束不会影响主线程的运行。
3.2 线程回收函数
int pthread_join(pthread_t thread, void **retval);
功能:通过该函数可以将指定的线程资源回收,该函数具有阻塞等待功能,如果指定的线程没有结束,则回收线程会阻塞。
参数:thread 要回收的子线程tid
retval 要回收的子线程返回值/状态。==》ptread_exit(值);
返回值:成功 0, 失败 -1;
- 无返回值
![]()
- 有返回值
子线程的回收策略:
1、如果预估子线程可以有限范围内结束则正常用pthread_join等待回收。
2、如果预估子线程可能休眠或者阻塞则等待一定时间后强制回收。
3、如果子线程已知必须长时间运行则,不再回收其资源。
3.3 线程的变量共享
四、线程的参数(返回值)
重点:类型强制转换
1、传参数
传整数 ===》int add(int a,int b); ///a b 形参
add(x,y); ////x y 实参pthread_create(&tid,NULL,fun,x);
fun ==>void * fun(void * arg);
2.传字符串
栈区字符数组:
字符串常量:
char *p = "hello";
堆区字符串;
char *pc = (char *)malloc(128);
ptread_create(&tid,NULL,fun,pc);pthread_join(tid,NULL);
free(pc);
fun(void *arg)
{
char * pc = (char *)arg ;
printf("%s \n",pc);
%c
}
3.传结构体
1、定义结构体类型
2、用结构体定义变量
3、向pthread_create传结构体变量
4、从fun子线程中获取结构体数据
注意:
地址有三种:
0、栈区变量 错误,子线程结束该地址失效。
1、全局变量 失去意义,本质可以直接访问。解决方案:
2、静态变量
3、堆区变量
五、分离属性及线程清理函数
5.1 分离属性
设置分离属性,目的线程消亡,自动回收空间(不能再调join)。(与回收相关)
int pthread_deatch(pthread_t thread);
功能,设置分离属性
参数,线程id号,填自己的id
5.2 线程清理
同步出现:
void pthread_cleanup_push(void (*routine)(void *), void *arg);
功能:注册一个线程清理函数
参数,routine,线程清理函数的入口
arg,清理函数的参数。
返回值,无
void pthread_cleanup_pop(int execute);
功能:调用清理函数
execute,非0 执行清理函数
0 ,不执行清理
返回值,无
process thread
fork pthread_create 创建
getpid,ppid, pthread_self 获得号
exit, pthread_exit 退出
wait,waitpid, pthread_join 回收
kill, pthread_cancel 发信号
atexit pthread_clean, 清理
exec system--->fork->exec (ls) 执行外部程序