线程

线程的表示

线程标识TID,表示线程的数据类型pthread_t。

获取自己的TID:

#include <pthread.h>
pthread_t pthread_self(void);
比较两个线程:

#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);  //相同返回非0,不相同返回0

创建线程

#include <pthread.h>
int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);

参数:

第一个参数thread用于存放新产生的线程的TID,函数的返回值存在这里

第二个参数attr是所创建线程的属性。通常为NULL,即系统默认属性

第三个参数start_routine是线程开始函数

第四个参数arg是线程开始函数的参数,而且是唯一参数。如果start_routine有多个参数,那么把他们封装在结构中。

终止线程

#include <pthread.h>
int pthread_exit(void *value_ptr);
pthread_exit函数终止自己的执行。

参数:

value_ptr是线程终止出口状态。当另一个线程调用pthread_join()等待该线程时,那个线程就可以得到value_ptr给出的值。value_ptr可以是一个数据结构。只有当线程是可汇合的线程时,value_ptr才非空,否则为NULL

#include <pthread.h>
int pthread_join(pthread_t thread, void **value_ptr);

这个函数会把调用这个函数的线程悬挂起来,等待thread指定的线程终止。如果value_ptr是非NULL,他所指的对象将存放线程thread终止时传递的值。而且这个函数还会释放thread线程占用的系统资源。

注册退出清理函数:pthread_cleanup_push,类似于进程的退出注册函数atexit一样。

i. 调用时机1pthread_exit

ii. 调用时机2:其他线程要求pthread_cancel取消本线程时,响应用

iii. 调用时机3:非0参数,使用pthread_clean_pop。参数0时,不调用直接删除

如果一个线程不是分离的,它的资源要在另一个线程调用pthread_join()与他汇合之后才被释放。这种线程就是可汇合的线程,否则是分离的线程。所以pthread_join函数等待的线程必须是可汇合的。

#include <pthread.h>
int a[SIZE], b[SIZE];
void max_fun(int *arg)
{
    int *ap = arg;
    ...
    pthread_exit((void *)&ap[k]);
 }
int main()
{
    ...
    int **ptr1, **ptr2;
    pthread_create(...);
    pthread_create(...);
    pthread_join(tid1, (void **)&ptr1);
    pthread_join(tid2, (void **)&otr2);
    ...
}
可汇合与分离的线程

#include <pthread.h>
int pthread_detach(pthread_t thread);
这个函数使一个原本可汇合的线程改变为分离的线程。这个函数对同一个线程只调用一次。

特殊属性的线程

线程属性:pthread_attr_t

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);    //初始化属性对象
int pthread_attr_destroy(pthread_attr_t *attr);
第一个函数初始化属性对象,传进去的参数只是一个指针,这个函数有两个动作,一个是为属性对象分配空间,一个是给他赋初值。

可以制定的属性有:

(1)分离状态:PTHREAD_CREATE_DETACHED(分离的线程),PTHREAD_CREATE_JOINABLE(可汇合的线程)

#include <pthread.h>
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

(2)栈大小

#include <pthread.h>
int pthread_attr_getstacksize(const pthread_attr_t *restrict attr, size_t *restrict stacksize);  
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

(3)栈地址

#include <pthread.h>
int pthread_attr_getstackaddr(const pthread_attr_t *restrict attr, void **restrict stackaddr);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr); 
也可以通过函数同时设置或获取栈地址和大小:

#include <pthread.h>
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
int pthread_attr_getstack(const pthread_attr_t *restrict attr, void **restrict stackaddr, size_t *restrict stacksize);

(4)栈溢出保护区大小:注意栈有向低地址延伸的,也有向高地址延伸的。

#include <pthread.h>
int pthread_attr_getguardsize(const pthread_attr_t *restrict attr, size_t *restrict guardsize);
int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);

线程同步的方法:

(1)互斥执行。两个线程必须依次访问某个共享对象

(2)条件同步。线程必须等待某个事件发生

(3)栅栏同步。控制线程执行过程中的汇合,比如在某处等齐所有线程

互斥变量

互斥变量的类型为pthread_mutex_t,使用之前必须初始化,且只能初始化一次,初始化方法:

#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
或者

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

互斥变量的初始化和销毁

int pthread_mutex_destroy(pthread_mutex_t *mutex);

互斥变量的属性

数据结构pthread_mutexattr_t,属性的初始化和销毁:

#include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

可定制的属性:

(1)共享属性:PTHREAD_PROCESS_PRIVATE(仅由同一个进程内的线程使用),PTHREAD_PROCESS_SHARED(可以由多个进程的线程使用)

(2)类型属性:PTHREAD_MUTEX_NORMAL(基本类型,如果在加锁状态,则阻塞直到该锁被释放才能对其成功加锁),PTHREAD_MUTEX_RECURSIVE(递归类型,允许同一个线程在对其解锁之前多次加锁,为了释放这种互斥变量,必须对他解锁相同的次数),PTHREAD_MUTEX_ERRORCHECK,PTHREAD_MUTEX_DEFAULT

#include <pthreadh>
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);
int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr, int *restrict type);

互斥变量的加锁与解锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
如果类型为PTHREAD_MUTEX_RECURSIVE,pthread_mutex_lock函数会维护互斥变量的锁计数器。每加一道锁计数器+1,每次解锁计数器-1.当锁为0时,置为未锁状态。

pthread_mutex_lock和pthread_mutex_trylock的不同之处在于,如果mutex当前已经被锁住,线程不会受阻,而是立即以EBUSY失败返回。但如果是PTHREAD_MUTEX_RECURSIVE类型并且已被调用线程占有,则mutex计数器+1,函数立即成功返回。

spin锁

当上锁受阻时,线程不必阻塞而是可以轮询直到获得锁为止。

读写锁

主要用于保护读操作频繁但写操作很少的共享数据。但是其上锁和解锁操作比互斥变量开销大。

条件变量

当线程访问某个共享数据,不仅需要互斥,还要求这个共享数据满足某种状态或条件,如果其他线程不改变这个状态,就无法继续处理。那么可以将自己加入到一个等待队列,然后阻塞自己并等待被生产线程唤醒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值