- 线程的同步与互斥
2019-12-07:
(POSIX中2种线程同步机制)
因线程共享进程的资源、地址空间,所以对该类资源进行操作时,一定要考虑线程间资源访问同步和互斥的问题;(2种同步机制也可互相通过调用对方来实现)
互斥锁:更适合用于同时可用的资源 是唯一的情况;
信号量:更适合用于同时可用的资源 为多个的情况;
- 互斥锁:针对线程
互斥锁是用一种简单的加锁方法来控制对共享资源的原子操作,一定程度上可以看做是全局变量。
互斥锁只有2中状态,即上锁和解锁(同一时刻只允许1个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行操作;若其他线程希望上锁,只能先挂起直到上锁的线程释放互斥锁为止)。
互斥锁保证让每个线程对共享资源按顺序进行原子操作。
互斥锁机制的基本函数:#include <pthread.h>, returen 0表示成功
初始化:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const
pthread_mutexattr_t *restrict attr);
// mutex互斥锁; attr互斥锁属性:快速(NULL默认)、递归、检错
上锁:
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);
初始化互斥锁时,有快速(默认阻塞等待)、递归、检错3种类型互斥锁,其区别在于其他未占用的互斥锁的线程在希望得到互斥锁时是否需要阻塞等待。
【互斥锁实验:】
使得原来独立无序的线程能够按顺序执行,先到先得锁,则先使用资源
- 信号量:针对进程或线程
信号量,即操作系统中的PV原子操作,主要用户进程或线程间的同步与互斥;其本质上是一个非负的整数计数器;被用来控制对共享资源的访问。
PV原子操作:是对整数计数器信号量sem的操作,P减V加;进程或线程根据信号量sem的值来判断是否对公共资源具有访问权限。(当sem>=0时,具有对公共资源的访问权限,否则没有,阻塞等待直到sem的值>=0为止)
PV原子操作使用场景:用户对进程或线程间同步或者互斥操作;
用于互斥操作:几个进程或线程只设置1个信号量sem;
用于同步操作:设置多个信号量,并安排不同的初始值来实现他们之间的顺序执行。
POSIX无名信号量常见函数:#include <semaphore.h>
初始化:
int sem_init(sem_t *sem, int pshared, unsigned int value);
// sem信号量指针; pshared初始为0,目前不支持进程间共享信号量; value信号量初始值
P操作:
int sem_wait(sem_t *sem); // sem<0时,阻塞等待
int sem_trywait(sem_t *sem); // sem<0时,立即返回错误值
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
sem_timedwait() is the same as sem_wait(), except that abs_timeout specifies a limit on the amount of time that the call should block if the decrement cannot be immediately performed. The abs_timeout argument points to a structure that specifies an absolute timeout in seconds and nanoseconds since the Epoch(00:00:00, 1 January 1970). This structure is defined as follows:
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds [0 .. 999999999] */
};
V操作:
int sem_post(sem_t *sem);
// 将sem值+1,同时发出信号来唤醒等待的进程
获取信号量的值:
int sem_getvalue(sem_t *sem, int *sval);
删除信号量:
Int sem_destroy(sem_t *sem);
【信号量实验】
使用信号量同步机制实现多线程之间的顺序访问
【总结】
使用信号量、互斥锁实现多线程之间的同步机制,两者那个更为合理?区别与联系是?
信号量:可以认为的控制多个线程之间的执行顺序
互斥锁:多个线程顺序执行:互斥锁是先到先得,谁先拿到互斥锁谁先执行。