因为一个进程中的所有线程共享进程的地址空间,所以要求对临界资源的访问要做到互斥和同步;使用互斥锁、读写锁可以实现线程间对临界资源访问时的互斥。
互斥锁
①初始化和销毁互斥锁
静态初始化互斥锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
动态初始化互斥锁:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,constpthread_mutexattr_t *restrict attr);
销毁互斥锁:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
②给互斥锁上锁和解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
函数功能:给互斥锁上锁,上锁不成功就阻塞
#include <pthread.h>
int pthread_mutex_trylock(pthread_mutex_t *mutex);
函数功能:尝试给互斥锁上锁,若上锁不成功就立即结束调用此函数,不会阻塞
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数功能:对互斥锁解锁
test:创建两个线程,分别对临界资源访问,在访问时利用互斥锁实现互斥。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int a = 0;
pthread_mutex_t mutex;
void *thread1(void *arg)
{
printf("thread1 start...\n");
pthread_mutex_lock(&mutex); //线程1访问临界资源前,先把互斥锁上锁
a = 10;
pthread_mutex_unlock(&mutex); //访问完临界资源,再把互斥锁解锁
printf("thread1 end...\n");
pthread_exit(NULL);
}
void *thread2(void *arg)
{
printf("thread2 start...\n");
pthread_mutex_lock(&mutex);
printf("a = %d\n", a);
pthread_mutex_unlock(&mutex);
printf("thread2 end...\n");
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
pthread_t tid[2];
pthread_create(&tid[0], NULL, thread1, NULL);
pthread_create(&tid[1], NULL, thread2, NULL);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
结果分析:thread2想要访问临界资源时,thread1已经持有这个互斥锁,所以thread2想要对这把共享互斥锁上锁时,就被阻塞,等待thread1释放锁才解除阻塞。
读写锁
pthread_rwlock_t读写锁有读锁和写锁两把锁,读锁和写锁是互斥的,即一个线程持有写锁对临界资源进行写操作时,不允许其他线程持有读锁对其读操作,反之亦然,但是多个线程可以同时持有读锁,同时进行读操作。
初始化互斥锁:
动态初始化:
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
atrr----->为NULL的话,默认初始化锁为读写锁
静态初始化:
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
销毁互斥锁:
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
给读写锁上写锁:
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
给读写锁上读锁:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//其他线程持有写锁时,就调用失败并使得线程阻塞
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);//调用失败不会阻塞,失败就立即结束调用
test:一个线程对临界资源写操作,其他线程进行读操作
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int a = 0;
pthread_rwlock_t rwlock;
void *thread1(void *arg) //写线程
{
for(int i = 0; i < 5; ++i)
{
pthread_rwlock_wrlock(&rwlock); //上写锁
sleep(2); //假设thread1对数据处理了2s
a++;
printf("thread1 write\n");
pthread_rwlock_unlock(&rwlock); //释放锁
}
}
void *thread2(void *arg)
{
for(int i = 0; i < 5; ++i)
{
pthread_rwlock_rdlock(&rwlock); //上读锁
printf("thread2 read: a = %d\n", a);
pthread_rwlock_unlock(&rwlock); //释放锁
sleep(1);
}
}
void *thread3(void *arg)
{
for(int i = 0; i < 5; ++i)
{
pthread_rwlock_rdlock(&rwlock); //上读锁
printf("thread3 read: a = %d\n", a);
pthread_rwlock_unlock(&rwlock); //释放锁
sleep(1);
}
}
int main(int argc, char const *argv[])
{
pthread_rwlock_init(&rwlock, NULL);
pthread_t tid[3];
pthread_create(&tid[0], NULL, thread1, NULL);
pthread_create(&tid[1], NULL, thread2, NULL);
pthread_create(&tid[2], NULL, thread3, NULL);
for(int i = 0; i < 3; ++i)
pthread_join(tid[i], NULL);
pthread_rwlock_destroy(&rwlock);
return 0;
}
结果分析:在thread1持有写锁进行写操作的2s期间内,thread2和thread3企图对持有读锁临界资源读操作,但是读锁和写锁是互斥的,所以thread2和thread3被阻塞,当thread1释放写锁后,thread2和thread3同时持有读锁,对临界资源同时进行读操作,此时,thread1试图持有写锁,但是由于读锁和写锁的互斥性,此时的thread1也被阻塞。