Linux线程的同步与互斥机制
拥有梦想是一种智力,实现梦想是一种能力。
概述
线程共享同一进程的地址空间,线程间通过全局变量交换数据进行通信。为了避免多个进程同时访问同一个共享资源而引发冲突,多个线程访问共享数据时需要同步或互斥机制
同步机制:指的是多个任务按照约定的先后次序相互配合完成一件事情
互斥机制:一次只允许一个任务(进程、线程)访问的共享资源
同步机制
信号量:代表某一类资源,其值表示系统中该资源的数量,由信号量来决定线程是继续运行还是阻塞等待。分为无名信号量(基于内存的信号量,本章讨论)和有名信号量。
就比如,我这里是网吧,那现在来了一个人开了一个机子,申请了一个资源,我这里可用电脑数量就会少一,如果有个人走了,关了一个自己,释放了一个资源,我这里可使用的电脑数量就会多一,电脑就可以理解成这个资源,这个初始值是多少呢,这个我们来定,根据需要写就可以
信号量是一个受保护的变量,只能通过三种操作来访问
- 初始化
- P操作(申请资源)
- V操作(释放资源)
要使用同步机制管理线程,线使用sem_init初始化信号量sem,指定资源的数量。完成任务后使用sem_post,如果要用资源使用sem_post,V操作作用是释放资源,增加空余资源 sem++ ; P操作作用是申请资源,如果sem是0,它就申请不到资源的,就不会执行申请,会等释放后才能申请,申请成功后减少空余资源sem--。
初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int val);
- 成功时返回0,失败时EOF
- sem 指向要初始化的信号量对象
- pshared 0 – 线程间 1 – 进程间
- val 信号量初值
释放资源(V)/申请资源(P)
#include <semaphore.h>
int sem_wait(sem_t *sem); P操作
int sem_post(sem_t *sem); V操作
- 成功时返回0,失败时返回EOF
- sem 指向要操作的信号量对象
示例
函数的功能是,主线程读取我们从终端写入的数据到buf,子线程sem_wait是等待主线程释放资源后进行相关操作。
-
#include <stdio.h>
-
#include <string.h>
-
#include <pthread.h>
-
-
char buf[32];
-
sem_t sem;
-
void *function(void *arg);
-
int main(void) {
-
pthread_t a_thread;
-
-
if (sem_init(&sem, 0, 0) < 0) {
-
perror(“sem_init”); exit(-1);
-
}
-
if (pthread_create(&a_thread, NULL, function, NULL) != 0) {
-
printf(“fail to pthread_create”);
-
exit(-1);
-
}
-
printf(“input ‘quit’ to exit\n”);
-
do {
-
fgets(buf, 32, stdin);
-
sem_post(&sem);
-
} while (strncmp(buf, “quit”, 4) != 0);
-
-
return 0;
-
}
-
-
void *function(void *arg) {
-
while ( 1 ) {
-
sem_wait(&sem);
-
printf(“you enter %d characters\n”, strlen(buf));
-
}
-
}
-
V操作表示已经把这个资源利用过了,释放一个资源;P操作是即将用到一个资源,申请一个资源。
比如一个人关了机子离开网吧,sem(信号量)控制另一个人来开机子。
sem表示资源的数量,释放是增加空余资源 sem++ ; 申请是减少空余资源sem--
这里sem的变化是 开始0 -> 主线程1 -> 子线程0 ->......
gcc 编译的时候注意加载库 -pthread
互斥机制
临界资源: 一次只允许一个任务(进程、线程)访问的共享资源
临界区:访问临界资源的代码
互斥机制:mutex互斥锁,任务访问临界资源前申请锁,访问完后释放锁
互斥锁的三种操作
- 初始化互斥锁
- 申请锁
- 释放锁
因为,互斥机制一次只允许一个任务(进程、线程)访问的共享资源。通过互斥锁构造这种机制,首先要pthread_mutex_init初始化互斥锁,然后我们在访问临界资源的代码之前用pthread_mutex_lock来给临界区·加锁·,结束再pthread_mutex_unlock释放锁。
初始化互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t * attr);
- 成功时返回0,失败时返回错误码
- mutex 指向要初始化的互斥锁对象
- attr 互斥锁属性,NULL表示缺省属性
申请锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
- 成功时返回0,失败时返回错误码
- mutex 指向要初始化的互斥锁对象
- 如果无法获得锁,任务阻塞
释放锁
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
- 成功时返回0,失败时返回错误码
- mutex 指向要初始化的互斥锁对象
- 执行完临界区要及时释放锁
示例
宏 _LOCK_ 为1表示使用互斥机制,保证主进程与子进程执行到临界区不能被切换,所以 value1 始终等于 value2 !
-
#include <stdio.h>
-
#include <pthread.h>
-
-
unsigned int count, value1, value2;
-
pthread_mutex_t lock;
-
-
void *function(void *arg);
-
int main(void) {
-
pthread_t a_thread;
-
-
if (pthread_mutex_init(&lock, NULL) != 0) {
-
printf(“fail to pthread_mutex_init\n”); exit(-1);
-
}
-
if (pthread_create(&a_thread, NULL, function, NULL) != 0) {
-
printf(“fail to pthread_create”); exit(-1);
-
}
-
while ( 1 ) {
-
count++;
-
#ifdef _LOCK_
-
pthread_mutex_lock(&lock);
-
#endif
-
value1 = count;
-
value2 = count;
-
#ifdef _LOCK_
-
pthread_mutex_unlock(&lock);
-
#endif
-
}
-
-
return 0;
-
}
-
-
void *function(void *arg) {
-
while ( 1 ) {
-
#ifdef _LOCK_
-
pthread_mutex_lock(&lock);
-
#endif
-
if (value1 != value2) {
-
printf(“value1 = %u, value2 = %u\n”, value1, value2);
-
usleep(100000);
-
}
-
#ifdef _LOCK_
-
pthread_mutex_unlock(&lock);
-
#endif
-
}
-
-
return NULL;
-
}
文章来源: blog.csdn.net,作者:hinzer,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/feit2417/article/details/81302501
- 点赞
- 收藏
- 关注作者
评论(0)