抱歉,我问的太明显了。我在Windows下编程多年。
目前我正在做一个在macOS下运行的项目。(我相信它在引擎盖下使用了Free BSD。
因此,我需要同步多个进程(一个是启动守护进程,其他是客户端进程)对共享资源的访问
我选择使用一个共享(命名)互斥体。
我看不出内核对命名互斥体的任何直接实现。我所能找到的都是使用共享内存的实现,如下所示:
1.使用shm_open
或shmget
+ shmat
创建/打开共享内存段
1.使用常规的pthread_mutex_t
,但使用属性初始化它:pthread_mutexattr_setpshared(&mtxAtt, PTHREAD_PROCESS_SHARED);
1.然后将其创建为常规互斥体:pthread_mutex_init
1.并使用它来锁定和解锁与pthread_mutex_lock
和pthread_mutex_unlock
。
这是可行的,除了一个边缘情况:
比方说,一个客户端通过调用pthread_mutex_lock
来获取这个共享互斥体,然后要么崩溃,要么被用户终止,因此它永远不会调用pthread_mutex_unlock
。(在微软的说法中,他们将互斥锁的状态称为"abandoned" mutex。在这种情况下,如果另一个进程试图获取这样的互斥体,这将导致锁定函数错误,以表示这种情况。
在我的例子中,对于macOS,如果我的启动守护程序试图在同一个共享互斥体上调用pthread_mutex_lock
(在它被“放弃”之后),它将永远死锁。
因此,我想知道,是否有一种方法可以确定互斥体是否处于这种“放弃”状态?(并且避免锁定这种互斥体的死锁以及潜在地死锁线程。)
编辑:在试图理解如何使用System V信号量时,作为评论中建议的IPC互斥体,我能够找到以下代码片段(使用AI):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
要初始化,请执行以下操作:
key_t key = ftok("/tmp/semfile", 1);
if (key < 0) {
perror("ftok");
exit(EXIT_FAILURE);
}
int semid = semget(key, 1, IPC_CREAT | 0666);
if (semid < 0) {
perror("semget");
exit(EXIT_FAILURE);
}
// initialize the semaphore with a value of 1
if (semctl(semid, 0, SETVAL, 1) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
然后输入mutex:
struct sembuf sops = { 0, -1, SEM_UNDO };
// acquire the semaphore (lock)
if (semop(semid, &sops, 1) < 0) {
perror("semop");
exit(EXIT_FAILURE);
}
离开它:
sops.sem_op = 1;
// release the semaphore (unlock)
if (semop(semid, &sops, 1) < 0) {
perror("semop");
exit(EXIT_FAILURE);
}
最后,清理:
// destroy the semaphore
if (semctl(semid, 0, IPC_RMID) < 0) {
perror("semctl");
exit(EXIT_FAILURE);
}
但问题是,它只在同一个过程中起作用。对于IPC的情况,我可以进入和离开,就好像每个进程中的信号量没有相互连接一样。
那里缺少了什么?
1条答案
按热度按时间o8x7eapl1#
好吧,我花了三天时间来做what on Windows,我花了不到一个小时。
**我的结论:**macOS没有可靠的IPC互斥。
因此,如果有人找到了符合我上面概述的标准的解决方案,我会很高兴听到它。
到目前为止,我已经调查过:
pthread_mutex_t
和共享内存的POSIX互斥锁(如我上面所示)缺少一个关键功能:PTHREAD_MUTEX_ROBUST_NP
或pthread_mutexattr_setrobust_np
。没有它们,它们就像信号灯一样。sem_open
),但是它们缺乏基本的保护需求,无法防止没有解锁它们的死进程(我在OP中描述的废弃互斥问题)。SEM_UNDO
标志来防止意外终止进程的方法(就像我在OP中展示的那样),但我没有找到一种方法来使它跨进程工作。而且(这些东西的)文档至少可以说是糟糕透顶。bind
函数只是返回errno
2。unlink
来删除一个命名对象时,除了调用close
之外,这种绝对愚蠢的设计模式完全消除了任何健壮实现的可能性。例如,如果一个进程崩溃,它会将一个命名对象留在未定义状态,供下一个想要使用它的进程使用:它怎么会知道发生了什么命名的对象是否仍在使用?或者它只是被遗弃了。解决这个问题的唯一方法是重新启动macOS。完全是碉堡!我真的很困惑我的发现,因为应该有跨进程工作的同步对象。他们是如何编写操作系统的?或者,每个人都只是使用文件,然后必须
unlink
他们?难怪有时我不得不重新启动Mac来修复应用程序中的一些问题。