如何正确销毁 C 中多个进程使用的共享未命名信号量?
How to properly destroy a shared unnamed semaphore used by multiple processes in C?
我有一个程序创建一些共享内存来共享一些数据和一些信号量,在那里写入一些数据,然后其他进程连接到它并读取该数据并执行一些操作,使用创建的未命名信号量在它们之间进行同步通过第一个过程。
在完成所有操作后,是否只有在所有其他进程都完成后才可以销毁信号量(使用sem_destroy())?或者如果我让第一个进程等待其他进程完成他们的工作然后销毁信号量会更好吗?有了这个,我想我应该实施任何沟通渠道,但不确定如何去做。
编辑:提供一些代码
这是我创建共享内存的简化过程(省略了错误处理):
int fd_shm = shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
/* Resize the memory segment */
ftruncate(fd_shm, sizeof(ShmExampleStruct))
/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0);
close(fd_shm);
sem_init(&(example_struct->sem), 1, 1)
在 ShmExampleStruct 中,我得到了数据和信号量。
在这段代码之后,它将一些数据写入 example_struct
读取过程代码可能是这样的:
/* We open the shared memory */
int fd_shm = shm_open(SHM_NAME, O_RDONLY, 0);
/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ, MAP_SHARED, fd_shm, 0);
close(fd_shm);
然后阅读 example_struct
如果我启动写进程,然后启动一些读进程,销毁信号量的最好方法是什么?理论上,写作过程应该在阅读过程之前开始和结束。
正如 Michael Kerrish 在 LPI 中所述(第 1103 页),"an unnamed semaphore should be destroyed before its underlying memory is deallocated"。
而且书上说"If the semaphore resides in a POSIX shared memory region",就是你的情况(example_struct->sem
),"then the semaphore should be destroyed only after all processes are not using the semaphore and before the shared memory object is unlinked with shm_unlink()
".
因此,只有在没有 processes/threads 等待时销毁未命名的信号量才是安全的。它会导致未定义的行为:(1) 如果一个信号量在其他 processes/threads 被阻塞时被破坏;和 (2) 如果使用了被破坏的信号量。
为了在您的情况下保证这一点,您需要使用 shm_unlink()
函数删除共享内存对象,然后才调用 sem_destroy()
。为此,您需要同步您的进程以安全地销毁信号量。
例如,如果您在父进程中使用 fork()
创建进程(读者和作者),那么您可以在所有子进程完成后销毁父进程中的共享内存和信号量。对于同步,您可以使用 wait()
函数。
我有一个程序创建一些共享内存来共享一些数据和一些信号量,在那里写入一些数据,然后其他进程连接到它并读取该数据并执行一些操作,使用创建的未命名信号量在它们之间进行同步通过第一个过程。
在完成所有操作后,是否只有在所有其他进程都完成后才可以销毁信号量(使用sem_destroy())?或者如果我让第一个进程等待其他进程完成他们的工作然后销毁信号量会更好吗?有了这个,我想我应该实施任何沟通渠道,但不确定如何去做。
编辑:提供一些代码
这是我创建共享内存的简化过程(省略了错误处理):
int fd_shm = shm_open(SHM_NAME, O_RDWR | O_CREAT | O_EXCL,S_IRUSR | S_IWUSR);
/* Resize the memory segment */
ftruncate(fd_shm, sizeof(ShmExampleStruct))
/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ | PROT_WRITE, MAP_SHARED,fd_shm, 0);
close(fd_shm);
sem_init(&(example_struct->sem), 1, 1)
在 ShmExampleStruct 中,我得到了数据和信号量。 在这段代码之后,它将一些数据写入 example_struct
读取过程代码可能是这样的:
/* We open the shared memory */
int fd_shm = shm_open(SHM_NAME, O_RDONLY, 0);
/* Map the memory segment */
ShmExampleStruct *example_struct = mmap(NULL, sizeof(*example_struct), PROT_READ, MAP_SHARED, fd_shm, 0);
close(fd_shm);
然后阅读 example_struct
如果我启动写进程,然后启动一些读进程,销毁信号量的最好方法是什么?理论上,写作过程应该在阅读过程之前开始和结束。
正如 Michael Kerrish 在 LPI 中所述(第 1103 页),"an unnamed semaphore should be destroyed before its underlying memory is deallocated"。
而且书上说"If the semaphore resides in a POSIX shared memory region",就是你的情况(example_struct->sem
),"then the semaphore should be destroyed only after all processes are not using the semaphore and before the shared memory object is unlinked with shm_unlink()
".
因此,只有在没有 processes/threads 等待时销毁未命名的信号量才是安全的。它会导致未定义的行为:(1) 如果一个信号量在其他 processes/threads 被阻塞时被破坏;和 (2) 如果使用了被破坏的信号量。
为了在您的情况下保证这一点,您需要使用 shm_unlink()
函数删除共享内存对象,然后才调用 sem_destroy()
。为此,您需要同步您的进程以安全地销毁信号量。
例如,如果您在父进程中使用 fork()
创建进程(读者和作者),那么您可以在所有子进程完成后销毁父进程中的共享内存和信号量。对于同步,您可以使用 wait()
函数。