线程
介绍线程的相关概念,以及相关函数。
1:在一个进程中,可以创建多个线程,各个线程共享使用进程的一些资源,同时各个线程又有自己的特定的资源。
关于线程主要考虑的就是线程的创建与同步
2:线程有一个自己的执行上下文,其中包括:
(1)线程ID
(2)一组寄存器值
(3)堆栈
(4)调度优先级
(5)信号掩码(signal mask)
(6) errno值
(7)线程自定义数据
3:线程ID
线程ID用pthread_t来表示,其类型在不同的系统中可能不同,有可能为一个整形,也可能为一个结构体。
常用函数有如下两个:
-
#include <pthread.h>
-
int pthread_equal(pthread_t tid1, pthread_t tid2);
-
// 比较两个线程id是否相同,相同就返回非0,否则返回0
-
-
pthread_t pthread_self(void);
-
// 返回线程的id
4:线程创建
-
#include <pthread.h>
-
-
int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
调用pthread_create创建一个线程,函数返回后,tidp指针所指向地方保存了线程ID, 第二个参数为创建线程的属性,可直接用NULL,这样会使用默认属性。
第三个参数为线程要执行的函数,第四个参数为该函数的参数。
调用pthread_create后,线程会自动开始执行start_rtn函数。
5:线程的终止及返回值
如果在一个线程中调用了exit, _Exit, _exit那么整个进程都会终止。
终止线程有三种方法:
(1)在线程函数中调用return语句
(2)被其他线程使用pthread_cancel函数进行终止
(3)调用pthread_exit自行终止。
线程终止时,return或者pthread_exit调用时,指定了线程函数的返回值,那该返回值可通过pthread_join()函数来获取。
-
#include<pthread.h>
-
-
void pthread_exit(void *rval_ptr);
-
-
int pthread_join(pthread_t tid, void **rval_ptr);
-
int pthread_cancel(pthread_t tid);
-
void pthread_cleanup_push(void (*rtn)(void *), void *arg);
-
void pthread_cleanup_pop(int execute);
因为线程函数的返回值为一个指针,因此pthread_join函数的第二个参数需要传入指针的指针来获得线程的返回值。
如果线程是因为pthread_cancel导致的终止,那么pthread_join获得的返回值为PTHREAD_CANCELED。
pthread_cleanup_push函数的作用是注册相应的cleanup函数,在线程退出之前或执行这些函数,类似于进程中的atexit
三种情况会调用这些cleanup函数
(1)pthread_exit调用后
(2)响应pthread_cancel函数
(3)pthread_cleanup_pop函数调用,且参数为非0值。
pthread_cleanup_pop的传入参数为0的时候,会取消上一个注册的cleanup函数。
可以看出线程使用return语句返回和使用pthread_exit返回的区别,使用return返回不会调用cleanup函数。
注意pthread_cleanup_push和pthread_cleanup_pop函数必须成对调用。
6:线程的状态
线程处于运行或退出状态中。意思是说,当一个线程执行完成后,系统会保留其返回值还有其他部分资源,这样在调用pthread_join的时候能获取其返回值。
在调用pthread_join之后,线程处于detached状态,这时线程才算完全退出,其相关资源也被收回。
可以让一个线程在创建时设定其detached属性,于是线程执行完后,系统自动回收其资源,这时调用pthread_join无法获得其返回值。
后面讲述如何改变线程的这个属性。
7:线程同步
由于多个线程之间可能会访问同样的资源,因此为保证一致性,需要进行同步。
使用到的同步工具就是互斥锁、读写锁、条件变量
8:互斥锁
-
#include <pthread.h>
-
-
PTHREAD_MUTEX_INITIALIZER
-
-
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
-
-
int pthread_mutex_destroy(pthread_mutex_t *mutex);
-
-
int pthread_mutex_lock(pthread_mutex_t *mutex);
-
int pthread_mutex_trylock(pthread_mutex_t *mutex);
-
-
int pthread_mutex_unlock(pthread_mutex_t *mutex);
-
-
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int pshared);
-
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
-
-
PTHREAD_MUTEX_NORMAL
-
PTHREAD_MUTEX_ERRORCHECK
-
PTHREAD_MUTEX_RECURSIVE
-
PTHREAD_MUTEX_DEFAULT
-
-
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);
-
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
相关的函数包含初始化与销毁互斥锁:pthread_mutex_init,pthread_mutex_destroy
使用互斥锁:pthread_mutex_lock,pthread_mutex_trylock,pthread_mutex_unlock。 trylock表示仅尝试获得锁,若无法获得,则直接返回。
互斥锁的属性设置与获取:包含两个属性process-shared属性和type
process-shared属性表示该互斥锁是否可以在多个进程中使用,其值可为PTHREAD_PROCESS_SHARED或者PTHREAD_PROCESS_PRIVATE。
type属性表示互斥锁类型。默认为PTHREAD_MUTEX_NORMAL。区别如下:
type relock without unlock unlock when not owned unlock when unlocked
PTHREAD_MUTEX_NORMAL 死锁 未定义 未定义
PTHREAD_MUTEX_ERRORCHECK 返回错误 返回错误 返回错误
PTHREAD_MUTEX_RECURSIVE 允许 返回错误 返回错误
但一个线程连续的lock一个互斥锁时,默认是出现死锁,如果要允许,必须设定属性为PTHREAD_MUTEX_RECURSIVE。
PTHREAD_MUTEX_RECURSIVE该属性主要用在将一个单线程的接口变成支持多线程的情况。
如果函数A调用了fun1和fun2,fun1和fun2都需要操作同一个全局变量。为了能多线程的调用函数A,需要在使用全局变量之前加锁。
如果fun1调用了fun2,如果使用默认的PTHREAD_MUTEX_NORMAL,则在fun1调用fun2之前需要unlock锁,但这是若有其他的线程调用了函数A,则
会出现问题,因此必须使用PTHREAD_MUTEX_RECURSIVE这样才能不需要unlock,继续在fun2中调用lock
fun1: fun2:
pthread_mutex_lock(mutex); pthread_mutex_lock(mutex);
// 访问全局变量 // 访问全局变量
.... pthread_mutex_unlock(mutex);
//调用fun2
fun2()
.....
pthread_mutex_unlock(mutex);
9:读写锁
读写锁,该锁有3中状态:读模式、写模式、unlock。
在读模式下,其他的线程仍然可进入读模式,但要进入写模式必须等待
在写模式下,其他线程无法进行读模式或者写模式。
-
#include <pthread.h>
-
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
-
-
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
-
-
int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock); // 请求进入读模式
-
int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock); // 请求进入写模式
-
int pthread_rwlock_unlock(pthread_rwlock_t* rwlock); // unlcok
-
-
int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);
-
int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);
待续................
阅读(2114) | 评论(0) | 转发(0) |