linux编程-线程

linux编程-线程


MUTEX

一.概述                                                  

    互斥量是线程同步的一种机制,用来保护多线程的共享资源。同一时刻,只允许一个线程对临界区进行访问。

    互斥量的工作流程:创建一个互斥量,把这个互斥量的加锁调用放在临界区的开始位置,解锁调用放到临界区的结束位置。当内核优先把某个线程调度到临界区的开始位置时,线程执行这个加锁调用,并进入临界区对资源进行操作。此时其他线程再被内核调度到这里的时候,由于该互斥量已被加锁状态,得不到锁会一直阻塞在这里,导致其他线程不能进入临界区,直到刚刚那个进入临界区的线程离开临界区并执行解锁调用。

二.函数接口                                           

1.初始化互斥量

互斥量是一个pthread_mutex_t类型的变量。

1.1:用宏常量初始化:

    pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

1.2:用函数初始化:

    int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);

    mutex:互斥量结构指针    

    attr:互斥量的属性结构指针

2.设置互斥量属性

    int pthread_mutexattr_settype(pthread_mutexattr_t *attr,inttype);

    attr:互斥量的属性结构指针

    type:PTHREAD_MUTEX_NORMAL(默认属性),PTHREAD_MUTEX_ERRORCHECK(会进行错误检查,速度比较慢),PTHREAD_MUTEX_RECURSIVE(递归锁)。对于递归锁,同一个线程对一个递归锁加锁多次,会有一个锁计数器,解锁的时候也需要解锁这个次数才能释放该互斥量。

3.加锁与解锁

    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_lock()得不到锁会阻塞,int pthread_mutex_trylock()得不到锁会立即返回,并返回EBUSY错误。

    还有一个pthread_mutex_timedlock()会根据时间来等待加锁,如果这段时间得不到锁会返回ETIMEDOUT错误!

    int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex,conststructtimespec *restrict abs_timeout);

4.销毁互斥量

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

    mutex:创建的互斥量指针



COND

一.概述                                                   

    条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区。条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行。通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行。

    条件变量总是和互斥量一起使用,互斥量保护着条件变量,防止多个线程对条件变量产生竞争。

二.函数接口                                            

1.初始化条件变量

1.1:宏常量初始化

    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

1.2:函数初始化

    int pthread_cond_init(pthread_cond_t *restrict cond,constpthread_condattr_t *restrict attr);

跟互斥量类似,cond是条件变量的结构指针,attr是条件变量属性的结构指针。

2.等待和通知条件变量

    int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex,conststructtimespec *restrict abstime);

    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

    int pthread_cond_broadcast(pthread_cond_t *cond);

    int pthread_cond_signal(pthread_cond_t *cond);

    等待函数里面,要传入一个互斥量。pthread_cond_timewait()可以指定一个时间来等待,如果规定的时间没有获得通知,就返回ETIMEDOUT错误。而pthread_cond_wait()会一直阻塞。

    通知函数,pthread_cond_signal()至少唤醒一个等待的线程,pthread_cond_broadcast()会唤醒在该条件变量上所有线程。

3.销毁条件变量

    int pthread_cond_destroy(pthread_cond_t *cond);


RDLOCK

一.概述                                                   

    读写锁与互斥量的功能类似,对临界区的共享资源进行保护!互斥量一次只让一个线程进入临界区,读写锁比它有更高的并行性。读写锁有以下特点:

    1.如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!

    2.如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!

二.函数接口                                           

1.创建读写锁

1.1:宏常量初始化

    pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

1.2:函数初始化

    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,constpthread_rwlockattr_t *restrict attr);

    rwlock:读写锁的pthread_rwlock_t结构指针

    attr:读写锁的属性结构指针。不需要别的属性默认为NULL。

2.读写锁加锁与解锁

    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

    rwlock:创建的读写锁指针

3.其他类型的加锁

    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

    int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock,conststructtimespec *restrict abs_timeout);

    int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock,conststructtimespec *restrict abs_timeout);

    try类函数加锁:如果获取不到锁,会立即返回错误EBUSY!

    timed类函数加锁:如果规定的时间内获取不到锁,会返回ETIMEDOUT错误!

4.销毁读写锁

    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);


SPIN

    自旋锁与互斥量功能一样,唯一一点不同的就是互斥量阻塞后休眠让出cpu,而自旋锁阻塞后不会让出cpu,会一直忙等待,直到得到锁!!!

    自旋锁在用户态使用的比较少,在内核使用的比较多!自旋锁的使用场景:锁的持有时间比较短,或者说小于2次上下文切换的时间。

    自旋锁在用户态的函数接口和互斥量一样,把pthread_mutex_xxx()中mutex换成spin,如:pthread_spin_init()。



BARRIER

一.概述                                                   

    barrier(屏障)与互斥量,读写锁,自旋锁不同,它不是用来保护临界区的。相反,它跟条件变量一样,是用来协同多线程一起工作!!!

    条件变量是多线程间传递状态的改变来达到协同工作的效果。屏障是多线程各自做自己的工作,如果某一线程完成了工作,就等待在屏障那里,直到其他线程的工作都完成了,再一起做别的事。举个通俗的例子:

    1.对于条件变量。在接力赛跑里,1号队员开始跑的时候,2,3,4号队员都站着不动,直到1号队员跑完一圈,把接力棒给2号队员,2号队员收到接力棒后就可以跑了,跑完再给3号队员。这里这个接力棒就相当于条件变量,条件满足后就可以由下一个队员(线程)跑。

    2.对于屏障。在百米赛跑里,比赛没开始之前,每个运动员都在赛场上自由活动,有的热身,有的喝水,有的跟教练谈论。比赛快开始时,准备完毕的运动员就预备在起跑线上,如果有个运动员还没准备完(除去特殊情况),他们就一直等,直到运动员都在起跑线上,裁判喊口号后再开始跑。这里的起跑线就是屏障,做完准备工作的运动员都等在起跑线,直到其他运动员也把准备工作做完!

二.函数接口                                           

1.创建屏障

    int pthread_barrier_init(pthread_barrier_t *restrict barrier,constpthread_barrierattr_t *restrict attr, unsigned count);

    barrier:pthread_barrier_t结构体指针

    attr:屏障属性结构体指针

    count:屏障等待的线程数目,即要count个线程都到达屏障时,屏障才解除,线程就可以继续执行

2.等待

    int pthread_barrier_wait(pthread_barrier_t *barrier);

    函数的成功返回值有2个,第一个成功返回的线程会返回PTHREAD_BARRIER_SERIAL_THREAD,其他线程都返回0。可以用第一个成功返回的线程来做一些善后处理工作。

3.销毁屏障

    int pthread_barrier_destroy(pthread_barrier_t *barrier);

你可能感兴趣的:(linux编程-线程)