LWP:轻量级进程,因为Linux下的线程是用进程模拟的,所以它比线程大一点,比进程小一点
在 Linux上线程函数位于 libpthread共享库中 ,因此在 编译时要加上 -lpthread选项。
一、创建线程:
thread->线程 id attr->线程属性(可分离,可结合(默认)) start_routine->创建的线程的执行流(即线程对应的函数) arg->执行流的参数
返回值
:
成功返回
0,
失败返回错误号。
以前学过的系统函数都是成功返回
0,
失败返回
-1,
而错误
号保存在全局量
errno
中。
而
pthread
库的函数都是通过返回值返回错误号
,
虽然每个线程也都
有一个
errno,
但这是为了兼容其它函数接口而提供的
,pthread
库本身并不使用它
,
通过返回值
返回错误码更加清晰。
在一个线程中调用 pthread_create()创建新的线程后,当前线程从 pthread_create()返回继续往下执行。
start_routine返回时, 这个线程就退出了 ,其它线程可以调用pthread_join得到start_routine 的返回值,类似于父进程调用 wait(2)得到子进程的退出 状态
等待进程的作用:1、避免僵尸进程;
2、读取子进程的退出结果
3、同步父子进程的执行流
二、获取线程 id
该函数是获取线程自己的 id ,功能相当于进程中的 getpid.
调用此函数获得的各个线程的
id
是不同的,但对于同一进程中的线程来说,它们的进程号都与创建它们的进程的 p
id
相同.
三 、只终止线程而不终止进程的三种方法
(1)从要终止的线程函数中 return ,但从主线程 return 相当于终止整个进程
(2)从线程自己内部调用函数 pthread_exit来终止自己:
retval->线程的退出码
retval
是
void *
类型
,
和线程函数返回值的用法一样
,
其它线程可以调用
pthread_join
获得这个指
针。
(3)一个线程可以调用函数 pthread_cancel 终止同一进程中的另一个线程(不要自己取消自己):
thread->要取消的线程的 id
用该函数终止线程时,线程的退出码是 -1,它是一个宏 ,PTHREAD_CANCELED
查看宏的指令:#grep -R PTHREAD_CANCELED /usr/include/
注意
:pthread_exit
或者
return
返回的指针所指向的内存单元必须是
全局
的或者是用
malloc
分 配的
,
不能在线程函数的栈上分配
,
因为当其它线程得到这个返回指针时线程函数已
经退出了。
四 、
线程等待
thread ->被等的那个线程的id retval->通过它得到线程的退出码
调用该函数的线程将挂起等待
,
直到
id
为
thread
的线程终止。
thread
线程以不同的方法终止
,
通
过
pthread_join
得到的终止状态是不同的
,
总结如下
:
1.
如果
thread
线程
通过
return
返回
,value_ptr
所指向的单元里存放的是
thread
线程函数的返
回值
。
2.
如果
thread
线程被别的线程调用
pthread_cancel
异常终掉
,value_ptr
所指向的单元里存放
的是常数
PTHREAD_CANCELED
。
3.
如果
thread
线程是
自己调用
pthread_exit
终止
的
,value_ptr
所指向的单元存放的是
传给
pthread_exit
的参数
。 如果对
thread
线程的终止状态不感兴趣
,
可以传
NULL
给
value_ptr
数。
一般情况下
,
线程终止后
,
其终止状态一直保留到其它线程调用
pthread_join
获取它的状态为
止。 但是线程也可以被置为
detach
状态
,
这样的线程一旦终止就立刻回收它占用的所有资源
,
而不保留终止状态。
不能对同一线程调用两次
pthread_join,
或者如果已经对一个线程调
用 了
pthread_detach
就不能再调用
pthread_join
了。
五、终止进程的方法
(1)从 main 函数 return
(2)从任意地方调用 exit(退出码)
六、上述函数的使用例子
八、线程的属性
线程的分离与结合
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
线程的分离状态决定一个线程以什么样的方式来终止自己。在非分离状态(即可结合的,joinable)情况下,原有的线程等待创建的线程结束;只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。
设置线程分离状态的函数为pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。
线程等待——正确处理线程终止
- #include <pthread.h>
- void pthread_exit(void *retval);
- void pthread_join(pthread_t th,void *thread_return);
- int pthread_detach(pthread_t th);
如果线程处于joinable状态,则只能被创建它的线程等待终止。
在Linux平台默认情况下,虽然各个线程之间是相互独立的,一个线程的终止不会去通知或影响其他的线程。
但是已经终止的线程的资源并不会随着线程的终止而得到释放,我们需要调用 pthread_join() 来获得另一个线程的终止状态并且释放该线程所占的资源。
(说明:线程处于joinable状态下)
调用该函数的线程将挂起,等待 th 所表示的线程的结束。 thread_return 是指向线程 th 返回值的指针。需要注意的是 th 所表示的线程必须是 joinable 的,即处于非 detached(游离)状态;并且只可以有唯一的一个线程对 th 调用 pthread_join() 。如果 th 处于 detached 状态,那么对 th 的 pthread_join() 调用将返回错误。
如果不关心一个线程的结束状态,那么也可以将一个线程设置为 detached 状态,从而让操作系统在该线程结束时来回收它所占的资源。将一个线程设置为detached 状态可以通过两种方式来实现。一种是调用 pthread_detach() 函数,可以将线程 th 设置为 detached 状态。另一种方法是在创建线程时就将它设置为 detached 状态,首先初始化一个线程属性变量,然后将其设置为 detached 状态,最后将它作为参数传入线程创建函数 pthread_create(),这样所创建出来的线程就直接处于 detached 状态。
创建 detach 线程:
- pthread_t tid;
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_create(&tid, &attr, THREAD_FUNCTION, arg);
总之为了在使用 pthread 时避免线程的资源在线程结束时不能得到正确释放,从而避免产生潜在的内存泄漏问题,在对待线程结束时,要确保该线程处于 detached 状态,否着就需要调用 pthread_join() 函数来对其进行资源回收。