linux 下有两种方式可以使线程终止,一种是通过调用return 从线程函数返回,第二种是通过调用函数
#include
voidpthread_exit(void *retavl);
需要注意的地方:一是,主线程中如果从main函数返回或是调用了exit函数退出主线程,则整个进程终止,此时所有的其他线程也将终止。另一种是,如果主线程调用pthread_exit函数,则仅仅是主线程消亡,进程不会结束,其他线程也不会结束,直到所有的线程都结束时,进程才结束。
线程的分离状态决定一个线程以什么样的方式来终止自己。通常采用了线程的默认属性,即为非分离状态,这种情况下,原有的线程等待创建的线程结束。只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。
在使用 Pthread 时避免线程的资源在线程结束时不能得到正确释放,从而避免产生潜在的内存泄漏问题,在对待线程结束时,要确保该线程处于 detached 状态,否着就需要调用 pthread_join() 函数来对其进行资源回收。
私有数据
进程内的所有线程共享进程的数据空间,所以全局变量为所有线程共有。在某些场景下,线程需要保存自己的私有数据,这时可以创建线程私有数据(Thread-specific Data)TSD来解决。在线程内部,私有数据可以被线程的各个接口访问,但对其他线程屏蔽。
线程私有数据采用了一键多值技术,及一个key对应多个值。访问数据都是通过键值来访问的。使用线程私有数据时,需要对每个线程创建一个关联 的key,linux中主要有四个接口来实现:
1、pthread_key_create:创建一个键
int pthread_key_create(pthread_key_t *key, void (*destr_function) (void*));
首先从linux的TSD池中分配一项,然后将其值赋给key供以后访问使用。接口的第一个参数是指向参数的指针,第二参数是函数指针,如果该指针不为空,那么在线程执行完毕退出时,已key指向的内容为入参调用destr_function(),释放分配的缓冲区以及其他数据。
key被创建之后,因为是全局变量,所以所有的线程都可以访问。各个线程可以根据需求往key中,填入不同的值,这就相当于提供了一个同名而值不同的全局变量,即一键多值。一键多值依靠的一个结构体数组,即
static struct pthread_key_struct pthread_keys[PTHREAD_KEYS_MAX] ={{0,NULL}};
创建一个TSD,相当于将结构体数组的某一个元素的seq值设置为为“in_use”,并将其索引返回给*key,然后设置destr_function()为destr()。pthread_key_create创建一个新的线程私有数据key时,系统会搜索其所在进程的key结构数组,找出一个未使用的元素,将其索引赋给*key。
2、pthread_setspecific:为指定键值设置线程私有数据
int pthread_setspecific(pthread_key_t key, const void *pointer);
该接口将指针pointer的值(指针值而非其指向的内容)与key相关联,用pthread_setspecific为一个键指定新的线程数据时,线程必须释放原有的数据用以回收空间。
3、pthread_getspecific:从指定键读取线程的私有数据
void * pthread_getspecific(pthread_key_t key);
4、pthread_key_delete:删除一个键
void * pthread_getspecific(pthread_key_t key);
该接口用于删除一个键,功能仅仅是将该key在结构体数组pthread_keys对应的元素设置为“un_use”,与改key相关联的线程数据是不会被释放的,因此线程私有数据的释放必须在键删除之前。
互斥锁:
为了排除竞争条件的影响,应该使一些操作变成“原子的”——这些操作既不能分割也不能中断。
当一个线程锁定了互斥锁后,其他线程也要求锁定这个互斥锁的时候,就会被阻塞;直到前面的线程解除锁定后,其他线程才可以解除阻塞恢复运行。
GNU/Linux保证线程在锁定互斥锁的过程中不会发生竞争条件,只有一个线程可以锁定互斥锁,其他线程的锁定请求都会被阻塞。
创建互斥锁(Mutex),需要:
创建一个pthread_mutex_t类型的变量,将其指针传入函数pthread_mutex_init中;该函数的第二个参数是指向一个mutex属性对象(这个对象用来指定mutex的属性)的指针。mutex对象只能初始化一次。
更简单的办法是,使用PTHREAD_MUTEX_INITIALIZER来获得默认属性的mutex对象:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
调用pthread_mutex_lock函数,如果mutex对象未被锁定,则此函数立即返回;如果已被锁定,则此函数阻塞此线程的执行,直到mutex被解除锁定。
每次解除锁定后,只有一个线程可以解除阻塞恢复执行,其他调用线程都会继续阻塞。选定的解除阻塞的线程是不可预知的。
调用pthread_mutex_unlock函数,可以解除调用线程对mutex对象的锁定。在锁定mutex的线程中,必须调用此函数以解除锁定。
函数说明:
需要的头文件:pthread.h
1)初始化互斥锁
函数原型:int pthread_mutex_init (pthread_mutex_t *mp, const pthread_mutex attr_t *mattr)
初始化互斥锁之前,必须将其所在的内存清零。
如果互斥锁已初始化,则它会处于未锁定状态。互斥锁可以位于进程之间共享的内存中或者某个进程的专用内存中。
2)锁定互斥锁
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_t mutex;
int ret;
ret = pthread_ mutex_lock(&mp); /* acquire the mutex */
函数说明:
当 pthread_mutex_lock() 返回时,该互斥锁已被锁定。调用线程是该互斥锁的属主。如果该互斥锁已被另一个线程锁定和拥有,则调用线程将阻塞,直到该互斥锁变为可用为止。