概述
01 原理
开辟一块共享内存,使得相关进程均可访问同一块区域,再将互斥锁定义在该区域(即共享内存)上,使得相关进程可以使用该锁。
02 进程间的互斥锁和线程间互斥锁的区别
函数pthread_mutex_init(互斥锁地址, 属性对象地址)
在定义一把线程锁的时候第二个参数通常传为NULL
,这样该锁默认只能被统一进程下的线程持有。
如果要将其定义为进程之间可以持有的互斥锁,则需要传入属性对象地址。
// 锁
pthread_mutex_t lock;
// 状态对象
pthread_mutexattr_t lock_attr;
// 初始化锁状态,设置状态状态为——进程共享
pthread_mutexattr_init(&lock_attr);
pthread_mutexattr_setpshared(&lock_attr, PTHREAD_PROCESS_SHARED);
// 用锁状态来初始化锁
pthread_mutex_init(&lock, &lock_attr);
// 使用时不牵扯状态对象,但状态对象在锁销毁时也要销毁
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
// 销毁锁和锁状态
pthread_mutex_destroy(&lock);
pthread_mutexattr_destroy(&lock_attr);
现在我们需要将其定义在共享内存上,这样该锁就可以被其他进程访问,否则不能达到效果,原因请参考Linux虚拟地址。
03 将锁定义在共享内存上
共享内存的开辟参考Linux共享内存。
04 Show me the code
父进程每次将共享内存上的变量加1,子进程每次将其加2,用定义在共享内存上的互斥锁维护该变量的累加操作原子性。
去掉两进程加锁、开锁的过程则结果出错(N越大越容易暴露问题)。
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
/**
* 返回一片共享内存标识符,用于后续获取该共享内存,以及销毁该共享内存
* INDEX_OF_KEY —— 自定义的该共享内存序号
* LENGTH —— 共享内存大小
*/
const int create_flag(const int INDEX_OF_KEY, const unsigned int LENGTH) {
// 生成key
const char* FILE_PATH = "./";
key_t key = ftok(FILE_PATH, INDEX_OF_KEY);
// 创建共享内存空间
const int FLAG = shmget(key, LENGTH, IPC_CREAT | 0666);
return FLAG;
}
// 定义进程锁结构体
typedef struct MUTEX_PACKAGE {
// 锁以及状态
pthread_mutex_t lock;
pthread_mutexattr_t lock_attr;
// 在共享内存中的标识符
int FLAG;
} mutex_package_t;
// 初始化进程锁结构体
const int init(void* pthis) {
mutex_package_t* mp = (mutex_package_t*)pthis;
// 初始化锁状态,设置状态状态为——进程共享
pthread_mutexattr_init(&(mp->lock_attr));
pthread_mutexattr_setpshared(&(mp->lock_attr), PTHREAD_PROCESS_SHARED);
// 用锁状态来初始化锁
pthread_mutex_init(&(mp->lock), &(mp->lock_attr));
return 0;
}
// 在共享内存上定义进程锁结构体并且返回其位置
mutex_package_t* create_mutex_package(const int INDEX) {
const int FLAG = create_flag(INDEX, sizeof(mutex_package_t));
mutex_package_t* mp = (mutex_package_t*)shmat(FLAG, NULL, SHM_R | SHM_W);
mp->FLAG = FLAG;
assert(init(mp) == 0);
return mp;
}
// 销毁进程锁结构体,利用其FLAG变量索引到其占用的共享内存并销毁
const int destory_mutex_package(mutex_package_t* mp) {
// 销毁锁和锁状态
pthread_mutex_destroy(&(mp->lock));
pthread_mutexattr_destroy(&(mp->lock_attr));
// 释放共享内存
assert(shmctl(mp->FLAG, IPC_RMID, NULL) == 0);
return 0;
}
int main() {
// 创建自定义进程锁
mutex_package_t* mp = create_mutex_package(111);
// 获取一片共享内存空间
const int FLAG = create_flag(222, sizeof(int));
volatile int* x = (int*)shmat(FLAG, NULL, 0);
// 创建新进程
int id = fork();
assert(id >= 0);
// 设置循环次数
const int N = 1000000;
// 父进程每次加1,子进程每次加2
int i;
for (i = 0; i < N; ++i) {
if (id > 0) { // 父进程
// 加锁
pthread_mutex_lock(&(mp->lock));
int temp = *x;
*x = temp+1;
// 解锁
pthread_mutex_unlock(&(mp->lock));
} else { // 子进程
// 加锁
pthread_mutex_lock(&(mp->lock));
int temp = *x;
*x = temp+2;
// 解锁
pthread_mutex_unlock(&(mp->lock));
}
}
// 等待循环完毕
sleep(1);
// 打印
printf("pid= %d, x_address= %x, x= %dn", getpid(), x, *x);
// 等待打印完毕
sleep(1);
// 销毁进程锁,释放申请的共享内存
if (id > 0) { // 父进程
destory_mutex_package(mp);
mp = NULL;
shmctl(FLAG, IPC_RMID, NULL);
x = NULL;
printf("父进程释放资源完毕n");
}
return 0;
}
05 结果
pid= 64735, x_address= c1f1000, x= 3000000
pid= 64737, x_address= c1f1000, x= 3000000
父进程释放资源完毕
最后
以上就是冷傲秀发为你收集整理的Linux进程间互斥锁 (共享内存实现)的全部内容,希望文章能够帮你解决Linux进程间互斥锁 (共享内存实现)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复