是否可以在 Linux/UNIX 上的多处理情况下使用互斥锁?

Posted

技术标签:

【中文标题】是否可以在 Linux/UNIX 上的多处理情况下使用互斥锁?【英文标题】:Is it possible to use mutex in multiprocessing case on Linux/UNIX ? 【发布时间】:2012-03-12 11:33:51 【问题描述】:

这是一道面试题。

是否可以在 Linux/UNIX 的多处理情况下使用互斥锁?

我的想法: 不,不同的进程有不同的内存空间。

mutex 仅用于多线程。

信号量用于多处理以进行同步。

对吗?

欢迎任何 cmets。

谢谢

【问题讨论】:

取决于“多处理”的含义。如果您按照 *** 定义,那么多处理将包括多线程。如果您的意思是“多个进程”,那么您是对的。 见***.com/a/28479697/2189128 【参考方案1】:

不完全是。 POSIX 线程有一个process-shared attribute 的概念,可用于创建可由多个进程操作的互斥锁。

您可以将这样的互斥锁放在共享内存中,以便多个进程都可以访问它。

LINUX 是否实现了这一点。我不确定,我从来不需要使用它,因为它看起来过于复杂。

有关属性的有用说明,请参阅我对this question 的回答。

【讨论】:

【参考方案2】:

是的,通常在 Linux 中,我们只有未命名的互斥体,因此它们无法在进程之间操作。我们需要一个信号量来克服这个问题。

在 Windows 中,它们有一个命名互斥锁的概念,它允许我们跨进程使用互斥锁。

【讨论】:

参见linux.die.net/man/3/pthread_mutexattr_init - LINUX 允许进程共享互斥锁。无论它们是否命名在这里都无关紧要,Linux 和 UNIX 可以通过附加到公共共享内存块来共享它们而无需命名。 是的,没错。您可以通过附加到共享块来使用它们。 :)【参考方案3】:

很有可能使用process-shared mutex。

事实上,现代应用程序更喜欢使用进程共享互斥锁以及进程共享条件变量而不是信号量,因为后者的灵活性较低。

我记得在 2004 年使用 Red Hat Linux,当时它支持进程共享互斥锁和条件变量。

【讨论】:

【参考方案4】:

互斥锁(互斥锁)防止多个线程 从同时执行代码的关键部分 访问共享数据(即互斥体用于序列化 线程的执行)。所有互斥锁必须是全局的。一种 通过 mutex_lock() 成功调用互斥锁 将导致另一个线程也试图锁定 相同的互斥锁阻塞,直到所有者线程通过方式解锁它 互斥锁()。同一进程中的线程或 其他进程内可以共享互斥锁。

互斥锁可以同步同一进程中的线程,或者 在其他进程中。互斥锁可用于同步 如果互斥体分配在进程之间的线程 可写内存并在协作进程之间共享 (参见 mmap(2)),并已为此任务初始化。

初始化

互斥体要么是进程内的,要么是进程间的,具体取决于 根据隐式或显式传递给 该互斥体的初始化。静态分配的互斥锁 不需要显式初始化;默认情况下,一个 静态分配的互斥锁用全零初始化 并且它的作用域被设置在调用进程内。

对于进程间同步,需要分配互斥锁 存储在这些进程之间共享的内存中。由于 这种互斥体的内存必须动态分配, 互斥锁需要使用 mutex_init() 显式初始化。

【讨论】:

另外,对于进程间同步,除了需要在共享内存中分配之外,互斥锁还必须使用属性 PTHREAD_PROCESS_SHARED,否则从另一个进程访问互斥锁会导致未定义的行为(看到这个:linux.die.net/man/3/pthread_mutexattr_setpshared):“进程共享属性设置为 PTHREAD_PROCESS_SHARED 以允许任何有权访问分配互斥锁的内存的线程对互斥锁进行操作,即使互斥锁是在内存中分配的被多个进程共享”【参考方案5】:

我一直在寻找一个命名的互斥锁,以便我可以确保在进程的生命周期内互斥(确保每个属性集只有一个进程运行)。我没有找到(看起来我可能还不够努力),所以我通过使用抽象的 UNIX 域套接字在 linux 中实现了我自己的伪命名互斥锁。只有对该套接字的单个 bind() 会成功。另一个好处是,如果进程终止,操作系统将清理抽象的 UNIX 域套接字,因此不会清理套接字本身。不幸的是,我不确定您是否可以“等待”这个伪互斥体可用。

抽象 UNIX 域套接字是名称以空字节开头的 UNIX 域套接字。但请注意,我相信整个缓冲区都被用作名称,因此您要确保不只是 memcpy 或 strcpy 将部分字符串放入其中,或者如果您确实确保首先用某个字符填充整个缓冲区.

除了第一个 bind() 之外的所有操作都将失败,并返回 EADDRINUSE 的 errno。

// Create an abstract socket to use as a mutex.                             

int err;
int mutex_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (mutex_sock == -1)
    
    err = errno;
    printf("main, failed creating mutex socket: %s\n",
            get_error_string(errno, error_string, sizeof(error_string)));
    log_event(LOG_LEVEL_ERROR, "main, failed creating mutex socket: "
            "%s", get_error_string(errno, error_string,
            sizeof(error_string)));
    errno = err;
    goto done;
    

// Bind to abstract socket.  We use this as a sort of named mutex.          

struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path + 1, socket_name, sizeof(addr.sun_path) - 2);
result = bind(mutex_sock, (struct sockaddr*) &addr, sizeof(addr));
if (result == -1)
    
    err = errno;
    if (errno == EADDRINUSE)
        
        printf("main, failed bind to mutex socket: %s.  "
                "Another instance must be running.\n",
                get_error_string(errno,
                error_string, sizeof(error_string)));
        log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: "
                "%s.  "
                "Another instance must be running.",
                get_error_string(errno,
                error_string, sizeof(error_string)));
        
    else
        
        printf("main, failed bind to mutex socket: %s\n",
                get_error_string(errno, error_string,
                sizeof(error_string)));
        log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: %s",
                get_error_string(errno, error_string,
                sizeof(error_string)));
        
    errno = err;
    goto done;
    

谢谢, 尼克

【讨论】:

以上是关于是否可以在 Linux/UNIX 上的多处理情况下使用互斥锁?的主要内容,如果未能解决你的问题,请参考以下文章

Java在Linux下 不能处理图形的解决办法

浅谈 unix, linux, ios, android 区别和联系

浅谈 unix, linux, ios, android 区别和联系

`xz` 的多处理器支持?

Linux 文本处理利器--Awk常用命令

如何在 Linux/Unix 系统中验证端口是不是打开