pthread_mutex_lock和已放弃的共享互斥锁

mlnl4t2r  于 2023-05-06  发布在  其他
关注(0)|答案(1)|浏览(202)

抱歉,我问的太明显了。我在Windows下编程多年。
目前我正在做一个在macOS下运行的项目。(我相信它在引擎盖下使用了Free BSD。
因此,我需要同步多个进程(一个是启动守护进程,其他是客户端进程)对共享资源的访问
我选择使用一个共享(命名)互斥体。
我看不出内核对命名互斥体的任何直接实现。我所能找到的都是使用共享内存的实现,如下所示:
1.使用shm_openshmget + shmat创建/打开共享内存段
1.使用常规的pthread_mutex_t,但使用属性初始化它:pthread_mutexattr_setpshared(&mtxAtt, PTHREAD_PROCESS_SHARED);
1.然后将其创建为常规互斥体:pthread_mutex_init
1.并使用它来锁定和解锁与pthread_mutex_lockpthread_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的情况,我可以进入和离开,就好像每个进程中的信号量没有相互连接一样。
那里缺少了什么?

o8x7eapl

o8x7eapl1#

好吧,我花了三天时间来做what on Windows,我花了不到一个小时。

**我的结论:**macOS没有可靠的IPC互斥。

因此,如果有人找到了符合我上面概述的标准的解决方案,我会很高兴听到它。
到目前为止,我已经调查过:

  • 通过pthread_mutex_t和共享内存的POSIX互斥锁(如我上面所示)缺少一个关键功能:PTHREAD_MUTEX_ROBUST_NPpthread_mutexattr_setrobust_np。没有它们,它们就像信号灯一样。
  • 命名信号量是存在的(通过sem_open),但是它们缺乏基本的保护需求,无法防止没有解锁它们的死进程(我在OP中描述的废弃互斥问题)。
  • System V显然提供了通过SEM_UNDO标志来防止意外终止进程的方法(就像我在OP中展示的那样),但我没有找到一种方法来使它跨进程工作。而且(这些东西的)文档至少可以说是糟糕透顶。
  • 在彻底绝望地寻找解决方案时,我甚至尝试使用“抽象UNIX域套接字”,如果进程死亡,它应该会自动关闭。某人有shown here。但是你猜怎么着,macOS似乎不支持它们,bind函数只是返回errno 2。
  • 然后我想通过共享内存实现我自己的互斥体,在其中保存一个锁定进程的线程ID。但是同样,没有同步原则可以跨进程工作。例如,没有命名事件这样的东西。可以使用命名信号量,但这又回到了我前面提到的限制。
  • 最后,当一个人需要调用unlink来删除一个命名对象时,除了调用close之外,这种绝对愚蠢的设计模式完全消除了任何健壮实现的可能性。例如,如果一个进程崩溃,它会将一个命名对象留在未定义状态,供下一个想要使用它的进程使用:它怎么会知道发生了什么命名的对象是否仍在使用?或者它只是被遗弃了。解决这个问题的唯一方法是重新启动macOS。完全是碉堡!

我真的很困惑我的发现,因为应该有跨进程工作的同步对象。他们是如何编写操作系统的?或者,每个人都只是使用文件,然后必须unlink他们?难怪有时我不得不重新启动Mac来修复应用程序中的一些问题。

相关问题