linux多线程

[toc]

在linux下,Pthread是一套通用的线程库,由POSIX提出,具有较好的移植性。

使用头文件<pthread.h>

线程基本操作

线程的创建与退出

pthead_create

1
int pthread_create(pthread_t *thread, pthread_attr_t * attr, void *(*start_routine)(void *), void *arg);

传入参数:thread为线程标识符,attr为线程属性设置,start_routine为线程函数起始地址,arg为传给start_routine的参数。

返回值:0成功,-1失败。

pthread_exit

线程可以通过主动调用该函数结束自身。

值得注意不能使用exit来结束当前线程,因为exit会终止进程,终止该进程中所有线程。

1
void pthread_exit(void *retval)

传入参数:retval为调用者线程的返回值。

pthread_join

该函数用于将当前线程挂起,值得被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。

1
int pthread_join ((pthread_t th, void 参考资料**thread_return))

传入参数:th为等待线程的标识符,thread_return为用户定义的指针,用于存储被等待线程的返回值(不为NULL)时。

修改线程的属性资源

参考资料:多线程属性pthread_attr详解

在thread_create函数中,我们可以自定义线程的属性。线程主要有如下的一些属性:绑定属性、分离属性、堆栈地址、堆栈大小、优先级。默认的属性是非绑定、非分离、1M的堆栈、与父进程优先级相同。

pthread_attr_init

线程属性的设置通常先调用该函数进行初始化,之后再调用相应的属性设置函数进行设置。

1
int pthread_attr_init(pthread_attr_t *attr)

传入参数: attr线程属性

返回值:成功0,失败-1

pthread_attr_setscope

1
2
int pthread_attr_getscope( const pthread_attr_t * attr, int * scope );
int pthread_attr_setscope( pthread_attr_t*, int scope );

传入参数:

  • attr线程属性
  • scope:PTHREAD_SCOPE_SYSTEM 绑定(系统级竞争资源),PTHREAD_SCOPE_PROCESS 非绑定(进程内竞争资源)

pthread_attr_setdetachstate

线程的分离状态决定一个线程以什么方式结束自己。默认情况下为非分离,此时原有的线程等待新线程的结束,只有当pthread_join返回时,新线程才算终止。而在分离状态下,新线程一旦运行结束马上释放资源。

需要注意,在分离状态下,如果某一个进程运行的飞快,在pthread_create函数返回前就终止了,它终止后就可能将线程号和系统资源给其他线程使用,这时调用pthread_create就可能返回错误的线程号。

1
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)

detachstate: PTHREAD_CREATE_DETACHED 分离, PTHREAD _CREATE_JOINABLE 非分离

调度策略的获取/设置

1
2
int pthread_attr_getschedpolicy(const pthread_attr_t *, int * policy)
int pthread_attr_setschedpolicy(pthread_attr_*, int policy)

传入参数:policy为调度策略,有若干种可能的情况:

  • SCHED_FIFO
  • SCHED_RR (轮转法)
  • SHCED_OTHER

前两种方法均支持优先级的使用,优先级从1-99,数值越大优先级越高。

优先级的获取/设置/最值查询

1
2
int pthread_attr_getschedparam(const pthread_attr_t *,struct sched_param *);
int pthread_attr_setschedparam(pthread_attr_t *,const struct sched_param *);

默认的结构大概是这样

1
2
3
struct sched_param{
int sched_priority;
};

可以通过如下两个函数获取系统支持的优先级的最值

1
2
int sched_get_priority_max( int policy );
int sched_get_priority_min( int policy );

线程访问控制

由于线程共享进程资源,因而需要考虑资源访问的问题。

mutex互斥锁

互斥锁的类型

参考资料 九、Linux下线程互斥锁类型及属性

  • PTHREAD_MUTEX_NORMAL: 标准互斥锁:第一次上锁成功,第二次上锁会阻塞。
    描述:
    此类型的互斥锁不会检测死锁。如果线程在不首先解除互斥锁的情况下尝试重新锁定该互斥锁,则会产生死锁。尝试解除由其他线程锁定的互斥锁会产生不确定的行为。如果尝试解除锁定的互斥锁未锁定,则会产生不确定的行为。

  • PTHREAD_MUTEX_ERRORCHECK: 检错互斥锁:第一次上锁成功,第二次上锁会出错。

    描述:
    此类型的互斥锁可提供错误检查。如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则会返回错误。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。

  • PTHREAD_MUTEX_RECURSIVE:递归互斥锁:第一次上锁成功,第二次上锁也会成功,内部计数。
    描述:操作操作
    如果线程在不首先解除锁定互斥锁的情况下尝试重新锁定该互斥锁,则可成功锁定该互斥锁。 与 PTHREAD_MUTEX_NORMAL 类型的互斥锁不同,对此类型互斥锁进行重新锁定时不会产生死锁情况。多次锁定互斥锁需要进行相同次数的解除锁定才可以释放该锁,然后其他线程才能获取该互斥锁。如果线程尝试解除锁定的互斥锁已经由其他线程锁定,则会返回错误。 如果线程尝试解除锁定的互斥锁未锁定,则会返回错误。

  • PTHREAD_MUTEX_DEFAULT:默认互斥锁:同标准的互斥锁
    描述:
    如果尝试以递归方式锁定此类型的互斥锁,则会产生不确定的行为。对于不是由调用线程锁定的此类型互斥锁,如果尝试对它解除锁定,则会产生不确定的行为。对于尚未锁定的此类型互斥锁,如果尝试对它解除锁定,也会产生不确定的行为。允许在实现中将该互斥锁映射到其他互斥锁类型之一。

对互斥锁的操作

互斥锁的创建

1
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)

mutexattr缺省时默认创建快速互斥锁(PTHREAD_MUTEX_DEFAULT)

互斥锁的操作

1
2
3
4
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_mutex_destroy(pthread_mutex_t *mutex,)

(望文生义即可.jpg)

信号量线程控制

功能参见OS教材即可。

头文件

#include <semaphore.h>

基本操作

1
int sem_init(sem_t *sem, int pshared, unsigned int value)

传入参数:

  • sem信号量
  • pshared决定信号量能在几个进程间共享,由于目前linux还不能实现进程间信号量的共享,所以该值只能取1
  • value信号初始值
1
2
3
4
5
int sem_wait(sem_t *sem)
int sem_trywait(sem_t *sem)
int sem_post(sem_t *sem)
int sem_getvalue(sem_t *sem)
int sem_destroy(sem_t *sem)

望文生义即可。