多线程同步控制
常用的同步控制方法:
- 互斥锁(Mutex)
- 信号量(Semaphore)
- 条件变量(Condition Variable)
- 读写锁(Read-Write Lock)
- 自旋锁(Spin Lock)
互斥锁(Mutex)
多个线程对某个只能独占使用的资源进行互斥访问可以使用互斥锁。
当某个线程调用 pthread_mutex_lock 函数时:
- 如果互斥锁已经处于锁定状态,该函数会阻塞调用线程的执行,直到其他线程解锁才可能从 pthread_mutex_lock 函数返回继续往下执行。
- 如果互斥锁处于未锁定状态,那么 pthread_mutex_lock 函数就加锁成功并立即返回,其他晚一步调用 pthread_mutex_lock 函数的所有线程都会陷入阻塞状态。
- 加锁成功的线程执行完需要保护的代码之后一旦解锁,那些处于阻塞状态的线程又会有一个线程取消阻塞继续往下执行(pthread_mutex_lock 函数返回了)。
头文件#include <pthread.h>
信号量(Semaphore)
一个特殊的全局变量,用于控制同时访问特定资源的线程数量,支持 P/V 操作,并且它们都是原子性操作。
信号量的值就表示当前可用资源的数量。
P 操作:即等待信号,调用 sem_wait 实现;
-
如果信号量的当前值大于 0,P 操作会将其 - 1并立即返回。
-
如果信号量的当前值等于 0,P操作将会阻塞当前线程,直到信号量的值大于 0 或被信号打断。
V 操作:即发送信号,调用 sem_post 实现;直接将当前信号量的当前值+ 1 并返回。
头文件#include <semaphore.h>
//多个线程同时使用,实现互斥
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define N 10
//volatile int use_flag = 1;
//pthread_mutex_t m = PTHREAD_COND_INITIALIZER;
sem_t s;
void* thr_fun(void* arg);
int main()
{
int i;
pthread_t tids[N];
srand(time(NULL));
//pthread_mutex_init(&m, NULL);
sem_init(&s, 0, 1);// 3为信号量的值,表可用资源的数量 // 0表不同进程线程空间不可共享,共享为1(多个进程的不同线程共抢一个厕所)
for(i = 0; i < N; i++)
{
if(pthread_create(&tids[i], NULL, thr_fun, (void*)(long)i))
{
perror("pthread_create");
}
}
for(i = 0; i < N; i++)
{
pthread_join(tids[i], NULL);
}
//pthread_mutex_destroy(&m); //销毁互斥锁
sem_destroy(&s);
return 0;
}
void* thr_fun(void* arg)
{
int i = (int)(long)arg;
//下面两条语句并非原子性操作,所以不太安全,有可能某个线程执行到一半的时候被打断。
//while (!use_flag);
//use_flag--;
//pthread_mutex_lock(&m); // 加锁,原子性操作
/*if(i == 5)
{
while(pthread_mutex_trylock(&m)) //尝试加锁,失败,不阻塞,立即返回
{
printf("我正在处理其他事情...\n");
sleep(1);
}
}
else pthread_mutex_lock(&m);
*/
// P 操作
sem_wait(&s);
printf("%d号进入厕所...\n", i);
sleep(rand() % 5 + 1); // 1s ~ 5s
printf("%d号离开厕所!\n", i);
//下面两条语句并非原子性操作,所以不太安全,有可能某个线程执行到一半的时候被打断。
//use_flag++;
//pthread_mutex_unlock(&m); //
// V 操作
sem_post(&s);
pthread_exit(NULL);
}