c - 进程之间共享的互斥锁不起作用
问题描述
我正在尝试在进程之间创建一个简单的共享互斥锁。这个想法是我将运行相同的可执行文件两次以创建两个进程,第一个进程应该创建一个共享互斥锁并将其锁定并休眠一段时间,同时另一个进程应该发现共享互斥锁被锁定并应该报告相同. 为此,我编写了以下代码 -
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MYMUTEX "/mymutex"
int main(int argc, char* argv[])
{
pthread_cond_t *cond;
pthread_mutex_t *mutex;
int cond_id, mutex_id;
int mode = S_IRWXU | S_IRWXG;
/* mutex */
mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR, mode);
printf("Mutex Id : %d\n", mutex_id);
if (mutex_id < 0) {
printf("shm_open failed\n");
return -1;
}
if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
printf("ftruncate failed\n");
return -1;
}
mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
if (mutex == MAP_FAILED) {
printf("mmap failed\n");
return -1;
}
printf("Mutex : %p\n", mutex);
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
if (pthread_mutex_trylock(mutex)) {
printf("Cannot acquire Lock. Some instance might be already running\n");
} else {
printf("Acquired Lock now sleeping...\n");
sleep(25);
pthread_mutex_unlock(mutex);
pthread_mutex_destroy(mutex);
shm_unlink(MYMUTEX);
}
return 0;
}
据我了解创建进程之间共享的互斥锁,它应该映射到共享内存,并且应该设置属性 PTHREAD_PROCESS_SHARED。但是当我从两个单独的控制台运行程序时得到的结果是 -
控制台 1:
[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7faf2c57a000
Acquired Lock now sleeping...
控制台 2:
[gbose@seadev20:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f6d5766a000
Acquired Lock now sleeping...
我在这里想念什么?我的直觉是,同时初始化互斥锁是这种意外行为的根本原因——如果这是正确的,那么还应该做些什么来检查互斥锁是否已经初始化?
更新:通过根据@Shawn 的评论添加 O_EXCL 来处理共享内存文件已经存在的情况,但我仍然看到 mmap() 返回的内存地址是粘贴在控制台输出上方的新地址。
mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
if (mutex_id < 0) {
mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
} else {
if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
printf("ftruncate failed\n");
return -1;
}
}
解决方案
感谢@Shawn 指出首先检查共享内存是否存在。检查共享内存对象是否已经存在,如果存在则不再初始化互斥锁。总结是如果我们重新初始化一个互斥锁,那么它的锁信息就会被覆盖,因此它不起作用。
mutex_id = shm_open(MYMUTEX, O_CREAT | O_RDWR | O_EXCL, mode);
if (mutex_id < 0) {
mutex_id = shm_open(MYMUTEX, O_RDWR, mode);
mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
if (mutex == MAP_FAILED) {
printf("mmap failed\n");
return -1;
}
} else {
if (ftruncate(mutex_id, sizeof(pthread_mutex_t)) == -1) {
printf("ftruncate failed\n");
return -1;
}
mutex = (pthread_mutex_t *) mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, mutex_id, 0);
if (mutex == MAP_FAILED) {
printf("mmap failed\n");
return -1;
}
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mutex, &mattr);
pthread_mutexattr_destroy(&mattr);
}
printf("Mutex Id : %d\n", mutex_id);
printf("Mutex : %p\n", mutex);
if (pthread_mutex_trylock(mutex)) {
printf("Cannot acquire Lock. Some instance might be already running\n");
} else {
printf("Acquired Lock now sleeping...\n");
sleep(25);
pthread_mutex_unlock(mutex);
pthread_mutex_destroy(mutex);
shm_unlink(MYMUTEX);
}
控制台 1
[gbose@seadev:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f3cd591c000
Acquired Lock now sleeping...
控制台 2
[gbose@seadev2:~/mutlti-threaded-client-server$]./mutex
Mutex Id : 3
Mutex : 0x7f09db159000
Cannot acquire Lock. Some instance might be already running
推荐阅读
- sql - Postgresql EXCLUDE 约束在 INSERT 时未触发 ON CONFLICT
- git - Git拒绝切换分支
- webusb - 如何在 SAMD51 或任何其他 MCU 上实现 WebUSB?
- symfony - 如何使用 PayumBundle 和 Paypal 测试测试值的否定响应
- angular - TypeScript Type 的等效 scala 类型是什么
- r - 按另一个因素分组的每个因素的计数
- android - 为什么改造忽略成功的响应代码?
- python - pandas apply function that returns more rows
- excel - 如何将 Excel 范围中的字符串列表分配给 Outlook VBA 变量?
- connector - 如何从我的 PowerApps 自定义连接器响应中提取字符串值?