如果我在使用 PTHREAD_PROCESS_SHARED 时不调用 pthread_mutex_destroy 会发生什么
What happens if I do not call pthread_mutex_destroy when using PTHREAD_PROCESS_SHARED
在 Linux 上,可以通过使用 PTHREAD_PROCESS_SHARED 属性在进程之间共享互斥量,然后将其保存在可供许多进程使用的映射文件中。
这是 https://linux.die.net/man/3/pthread_mutexattr_init 中执行上述工作的示例:
For example, the following code implements a simple counting semaphore in a mapped file that may be used by many processes.
/* sem.h */
struct semaphore {
pthread_mutex_t lock;
pthread_cond_t nonzero;
unsigned count;
};
typedef struct semaphore semaphore_t;
semaphore_t *semaphore_create(char *semaphore_name);
semaphore_t *semaphore_open(char *semaphore_name);
void semaphore_post(semaphore_t *semap);
void semaphore_wait(semaphore_t *semap);
void semaphore_close(semaphore_t *semap);
/* sem.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include "sem.h"
semaphore_t *
semaphore_create(char *semaphore_name)
{
int fd;
semaphore_t *semap;
pthread_mutexattr_t psharedm;
pthread_condattr_t psharedc;
fd = open(semaphore_name, O_RDWR | O_CREAT | O_EXCL, 0666);
if (fd < 0)
return (NULL);
(void) ftruncate(fd, sizeof(semaphore_t));
(void) pthread_mutexattr_init(&psharedm);
(void) pthread_mutexattr_setpshared(&psharedm,
PTHREAD_PROCESS_SHARED);
(void) pthread_condattr_init(&psharedc);
(void) pthread_condattr_setpshared(&psharedc,
PTHREAD_PROCESS_SHARED);
semap = (semaphore_t *) mmap(NULL, sizeof(semaphore_t),
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
close (fd);
(void) pthread_mutex_init(&semap->lock, &psharedm);
(void) pthread_cond_init(&semap->nonzero, &psharedc);
semap->count = 0;
return (semap);
}
semaphore_t *
semaphore_open(char *semaphore_name)
{
int fd;
semaphore_t *semap;
fd = open(semaphore_name, O_RDWR, 0666);
if (fd < 0)
return (NULL);
semap = (semaphore_t *) mmap(NULL, sizeof(semaphore_t),
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
close (fd);
return (semap);
}
void
semaphore_post(semaphore_t *semap)
{
pthread_mutex_lock(&semap->lock);
if (semap->count == 0)
pthread_cond_signal(&semapx->nonzero);
semap->count++;
pthread_mutex_unlock(&semap->lock);
}
void
semaphore_wait(semaphore_t *semap)
{
pthread_mutex_lock(&semap->lock);
while (semap->count == 0)
pthread_cond_wait(&semap->nonzero, &semap->lock);
semap->count--;
pthread_mutex_unlock(&semap->lock);
}
void
semaphore_close(semaphore_t *semap)
{
munmap((void *) semap, sizeof(semaphore_t));
}
The following code is for three separate processes that create, post, and wait on a semaphore in the file /tmp/semaphore. Once the file is created, the post and wait programs increment and decrement the counting semaphore (waiting and waking as required) even though they did not initialize the semaphore.
/* create.c */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_create("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_close(semap);
return (0);
}
/* post */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_open("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_post(semap);
semaphore_close(semap);
return (0);
}
/* wait */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_open("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_wait(semap);
semaphore_close(semap);
return (0);
}
但是在共享互斥量上调用 pthread_mutex_destroy() 很棘手,因为它可能会导致其他进程出错,而且上面的示例也没有调用 pthread_mutex_destroy()。所以我想不要破坏它。
我的问题是:如果我初始化一个 PTHREAD_PROCESS_SHARED 互斥锁,将它保存到映射文件并在许多进程中永久使用它而不调用 pthread_mutex_destroy() 或重新初始化它是否安全?
My question is: Is it safe if I init a PTHREAD_PROCESS_SHARED mutex, save it to a mapped file and use it forever on many processes without calling pthread_mutex_destroy() or re-initialize it?
允许进程共享的互斥体比初始化它的进程存在时间更长。如果将这样的互斥量映射到持久性常规文件,那么它的状态将无限期地持续存在,即使没有进程映射它也是如此。只要保持其状态的完整性——包括但不限于没有进程通过 pthread_mutex_destroy()
破坏它——新进程就可以映射它并使用它。也就是说,你所描述的语义是明确的。
但是安全吗?不是特别.
第一个问题是您需要知道何时创建它,并且在创建时需要避免竞争条件。如果您依赖经常使用互斥锁的进程在需要时对其进行初始化,那么您必须确保在文件尚不存在时恰好有一个进程创建并初始化它。
另一个问题是,使用像这样的长寿命共享互斥锁会产生大量故障。例如,如果程序在锁定互斥量时崩溃,那么它将保持锁定状态,直到您采取某种手动纠正措施。或者,如果映射文件被直接操作,那么互斥状态很容易被破坏,在所有使用它的程序中产生未定义的行为——甚至在重新启动时也是如此。
如果你真的需要一个持久化的同步对象,那么我建议考虑a POSIX named semaphore。它是为此目的而设计的,考虑了上述注意事项和其他因素。然而,它有所不同,因为此类信号量驻留在内核中并具有内核持久性,因此它们不会在重新启动后持续存在(这通常是 good 事情),并且它们不易受影响普通文件操作。
或者,您可以考虑 a System V semaphore。这是一个较旧的信号量实现,也具有内核持久性。它的界面比 POSIX 信号量的界面笨拙得多,但它有一些 POSIX 信号量没有的有用特性,例如当持有一个锁定的进程终止时提供自动解锁(甚至异常终止) ).
在 Linux 上,可以通过使用 PTHREAD_PROCESS_SHARED 属性在进程之间共享互斥量,然后将其保存在可供许多进程使用的映射文件中。
这是 https://linux.die.net/man/3/pthread_mutexattr_init 中执行上述工作的示例:
For example, the following code implements a simple counting semaphore in a mapped file that may be used by many processes.
/* sem.h */
struct semaphore {
pthread_mutex_t lock;
pthread_cond_t nonzero;
unsigned count;
};
typedef struct semaphore semaphore_t;
semaphore_t *semaphore_create(char *semaphore_name);
semaphore_t *semaphore_open(char *semaphore_name);
void semaphore_post(semaphore_t *semap);
void semaphore_wait(semaphore_t *semap);
void semaphore_close(semaphore_t *semap);
/* sem.c */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <pthread.h>
#include "sem.h"
semaphore_t *
semaphore_create(char *semaphore_name)
{
int fd;
semaphore_t *semap;
pthread_mutexattr_t psharedm;
pthread_condattr_t psharedc;
fd = open(semaphore_name, O_RDWR | O_CREAT | O_EXCL, 0666);
if (fd < 0)
return (NULL);
(void) ftruncate(fd, sizeof(semaphore_t));
(void) pthread_mutexattr_init(&psharedm);
(void) pthread_mutexattr_setpshared(&psharedm,
PTHREAD_PROCESS_SHARED);
(void) pthread_condattr_init(&psharedc);
(void) pthread_condattr_setpshared(&psharedc,
PTHREAD_PROCESS_SHARED);
semap = (semaphore_t *) mmap(NULL, sizeof(semaphore_t),
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
close (fd);
(void) pthread_mutex_init(&semap->lock, &psharedm);
(void) pthread_cond_init(&semap->nonzero, &psharedc);
semap->count = 0;
return (semap);
}
semaphore_t *
semaphore_open(char *semaphore_name)
{
int fd;
semaphore_t *semap;
fd = open(semaphore_name, O_RDWR, 0666);
if (fd < 0)
return (NULL);
semap = (semaphore_t *) mmap(NULL, sizeof(semaphore_t),
PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
close (fd);
return (semap);
}
void
semaphore_post(semaphore_t *semap)
{
pthread_mutex_lock(&semap->lock);
if (semap->count == 0)
pthread_cond_signal(&semapx->nonzero);
semap->count++;
pthread_mutex_unlock(&semap->lock);
}
void
semaphore_wait(semaphore_t *semap)
{
pthread_mutex_lock(&semap->lock);
while (semap->count == 0)
pthread_cond_wait(&semap->nonzero, &semap->lock);
semap->count--;
pthread_mutex_unlock(&semap->lock);
}
void
semaphore_close(semaphore_t *semap)
{
munmap((void *) semap, sizeof(semaphore_t));
}
The following code is for three separate processes that create, post, and wait on a semaphore in the file /tmp/semaphore. Once the file is created, the post and wait programs increment and decrement the counting semaphore (waiting and waking as required) even though they did not initialize the semaphore.
/* create.c */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_create("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_close(semap);
return (0);
}
/* post */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_open("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_post(semap);
semaphore_close(semap);
return (0);
}
/* wait */
#include "pthread.h"
#include "sem.h"
int
main()
{
semaphore_t *semap;
semap = semaphore_open("/tmp/semaphore");
if (semap == NULL)
exit(1);
semaphore_wait(semap);
semaphore_close(semap);
return (0);
}
但是在共享互斥量上调用 pthread_mutex_destroy() 很棘手,因为它可能会导致其他进程出错,而且上面的示例也没有调用 pthread_mutex_destroy()。所以我想不要破坏它。
我的问题是:如果我初始化一个 PTHREAD_PROCESS_SHARED 互斥锁,将它保存到映射文件并在许多进程中永久使用它而不调用 pthread_mutex_destroy() 或重新初始化它是否安全?
My question is: Is it safe if I init a PTHREAD_PROCESS_SHARED mutex, save it to a mapped file and use it forever on many processes without calling pthread_mutex_destroy() or re-initialize it?
允许进程共享的互斥体比初始化它的进程存在时间更长。如果将这样的互斥量映射到持久性常规文件,那么它的状态将无限期地持续存在,即使没有进程映射它也是如此。只要保持其状态的完整性——包括但不限于没有进程通过 pthread_mutex_destroy()
破坏它——新进程就可以映射它并使用它。也就是说,你所描述的语义是明确的。
但是安全吗?不是特别.
第一个问题是您需要知道何时创建它,并且在创建时需要避免竞争条件。如果您依赖经常使用互斥锁的进程在需要时对其进行初始化,那么您必须确保在文件尚不存在时恰好有一个进程创建并初始化它。
另一个问题是,使用像这样的长寿命共享互斥锁会产生大量故障。例如,如果程序在锁定互斥量时崩溃,那么它将保持锁定状态,直到您采取某种手动纠正措施。或者,如果映射文件被直接操作,那么互斥状态很容易被破坏,在所有使用它的程序中产生未定义的行为——甚至在重新启动时也是如此。
如果你真的需要一个持久化的同步对象,那么我建议考虑a POSIX named semaphore。它是为此目的而设计的,考虑了上述注意事项和其他因素。然而,它有所不同,因为此类信号量驻留在内核中并具有内核持久性,因此它们不会在重新启动后持续存在(这通常是 good 事情),并且它们不易受影响普通文件操作。
或者,您可以考虑 a System V semaphore。这是一个较旧的信号量实现,也具有内核持久性。它的界面比 POSIX 信号量的界面笨拙得多,但它有一些 POSIX 信号量没有的有用特性,例如当持有一个锁定的进程终止时提供自动解锁(甚至异常终止) ).