本文demo运行在阿里云的服务器,Centos系统
首先复习进程和线程的资源关系。
进程内典型全局资源如下:
1)代码区:这意味着当前进程空间内所有的可见的函数代码,对于每个线程来说,也是可见的
2)静态存储区:全局变量,静态空间
3)动态存储区:堆空间
线程内典型的局部资源:
1)本地栈空间:存放本线程的函数调用栈,函数内部的局部变量等
2)部分寄存器变量:线程下一步要执行代码的指针偏移量
linux下的线程以进程PCB模拟,可以认为是轻量级进程。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*star t_routine)(void*), void *arg)
thread:返回线程ID
attr:设置线程的属性,attr为NULL表⽰使⽤用默认属性
start_routine:是个函数地址,线程启动后要执⾏行的函数
arg:传给线程启动函数的参数//返回值:
成功返回0,失败返回错误码
int pthread_join(pthread_t thread, void **value_ptr)
thread:线程ID
value_ptr:这个指针指向pthread_exit的参数,pthread_exit的参数用来指向线程的返回值
返回值:成功返回0,失败返回退出码
当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。当 pthread_join() 函数返回后,被调用线程才算真正意义上的结束,它的内存空间也会被释放(如果被调用线程是非分离的)。这里有三点需要注意:
A:被释放的内存空间仅仅是系统空间,你必须手动清除程序分配的空间,比如 malloc() 分配的空间。
B:一个线程只能被一个线程所连接。
C:被连接的线程必须是非分离的,否则连接会出错。
我们可以尝试创建一下线程
运行,
我们会发现,线程运行是没有必然顺序的,系统自动决定线程运行次序。
利用
查询,可以看到 所谓多线程,
struct task_struct {
...
pid_t pid;//线程id
pid_t tgid;//相当于用户层面的进程id
...
struct task_struct *group_leader;
...
struct list_head thread_group;
...
};
POSIX标准又要求进程内的所有线程调用getpid函数时返回相同的进程ID。所以Linux内核又引入了线程组的概念。pid实则是同一个进程,而LWP则是区分线程,系统调度的最小单位是线程,那么区分单位则来自LWP。
LWP:线程ID,代表线程组中的pid。
而NLWP则代表线程数目,我们demo中有thread1 和主线程
线程的终止
一个线程调用pthread_ cancel来终结另外一个线程
void pthread_exit(void *value_ptr)
终止自己(线程)
value_ptr是一个输出型参数,这个指针指向一块空间,这个空间包括一些退出信息。这个参数不能指向一个局部变量,一定要是全局变量或者是malloc出来的空间,因为当其他线程得到这个值时,该线程已经退出,局部变量已经全部销毁
返回值:无返回值int pthread_cancel(pthread_t thread)
终止其他线程
pthread_t类型的线程ID
取消成功返回0,失败返回错误码
线程的等待和分离
join开头给出,下面给出detach。
//线程组内其他线程对目标线程分离
int pthread_detach(pthread_t thread);
//线程自己分离
int pthread_detach(pthread_self());
线程只存在下面2种情况
线程的join和detach(unjoinable)
Joinable状态,新创建的线程是可以被等待的,当线程退出之后,需要通过pthread_join()对该线程等待,否则无法释放该线程所占用的资源,从而造成资源泄露。
如果我们不想知道某个线程的返回值状态,对该线程join其实是一种负担。在这种情况下,我们可以通过分离线程告诉OS,当线程退出时,自动的释放线程资源。
二者的区别在于是否依附于主线程,join操作后,主线程会阻塞等待join线程,detach则是分离开,由系统回收资源。