![](/img/trans.png)
[英]POSIX unnamed semaphore in shared memory is not responding to post or wait
[英]How to write unnamed Posix Semaphore to Shared Memory?
我想為共享 memory 寫一個信號量。 我的第一個想法是將 mmap 返回的指針傳遞給sem_init()
:
#include <stdio.h>
#include <semaphore.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
sem_t *sem_ptr;
int shm_fd = shm_open("Shm", O_CREAT | O_RDWR, DEFFILEMODE);
fprintf(stderr, "%s\n", strerror(errno));
sem_ptr = mmap(NULL, sizeof(sem_t), PROT_WRITE, MAP_SHARED, shm_fd, 0);
fprintf(stderr, "%p\n", strerror(errno));
sem_init(sem_ptr, 1, 1);
fprintf(stderr, "%s\n", strerror(errno));
sem_destroy(sem_ptr);
return 0;
}
但這會導致此錯誤(調用sem_init()
時): Process finished with exit code 135 (interrupted by signal 7: SIGEMT
)
然后我嘗試使用sem_t
變量初始化信號量並將其寫入共享的 memory:
int main(void)
{
sem_t *sem_ptr;
sem_t s;
int shm_fd = shm_open("Shm", O_CREAT | O_RDWR, DEFFILEMODE);
fprintf(stderr, "%s\n", strerror(errno));
sem_ptr = mmap(NULL, sizeof(sem_t), PROT_WRITE, MAP_SHARED, shm_fd, 0);
fprintf(stderr, "%p\n", strerror(errno));
sem_init(&s, 1, 1);
fprintf(stderr, "%s\n", strerror(errno));
*sem_ptr = s;
sem_destroy(&s);
return 0;
}
現在行*sem_ptr = s;
導致與第一個程序相同的錯誤
任何人都可以幫助我嗎?
您創建信號量的第一個策略是正確的。 您不一定可以將sem_t
object 復制到不同的 memory 地址並使其仍然有效。
我不確定你為什么會得到SIGEMT
,我認為現代 Unix 從未生成過它。 但是當我在我的計算機上運行您的任何一個程序時,它們會因SIGBUS
而崩潰,這使我發現了一個我知道如何修復的錯誤。 當您mmap
一個文件(共享的 memory object 被認為是一個文件),並且您在mmap
調用中要求的大小大於文件時,然后您訪問 ZCD69B4957F06CD818D7BF3D61980E2 之外的文件末尾區域足以讓 CPU 捕獲它),你得到一個SIGBUS
。 讓我引用shm_open
聯機幫助頁的關鍵部分:
O_CREAT
:如果共享 memory object 不存在,則創建它。 [...]一個新的共享 memory object 最初的長度為零 - 可以使用 ftruncate(2) 設置 object 的大小。
您需要做的是在shm_fd
上調用ftruncate
以使共享的 memory object 大到足以容納信號量。
您應該同時修復一些不太重要的錯誤:
如果您為它們提供的偏移量或大小不是系統頁面大小的倍數,則所有與 memory 映射一起使用的系統調用都可能會出現故障。 (他們應該為您收集信息,但從歷史上看,這方面存在很多錯誤。)您可以通過調用sysconf(_SC_PAGESIZE)
獲取系統頁面大小,然后使用如下所示的小助手 function 進行收集。
大多數 C 庫函數即使成功,也允許將errno
為非零值。 您應該在打印strerror(errno)
之前檢查每個 function 是否實際失敗。 (在下面的代碼中,為了簡潔起見,我使用了perror
。)
共享 memory object 的名稱必須以斜杠開頭,后跟最多NAME_MAX
個非斜杠字符。
sem_init
可以讀取和寫入 sem_ptr 指向的sem_ptr
,隨后使用sem_wait
和sem_post
肯定會,所以你應該在mmap
調用中使用PROT_READ|PROT_WRITE
。
總而言之,這是您的第一個程序的修訂版,可在我的計算機上運行。 由於SIGEMT
的事情,我不能 promise 它會為你工作。
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#ifndef DEFFILEMODE
# define DEFFILEMODE 0666
#endif
static long round_up(long n, long mult)
{
return ((n + mult - 1) / mult) * mult;
}
int main(void)
{
long pagesize;
long semsize;
sem_t *sem_ptr;
int shm_fd;
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize == -1) {
perror("sysconf(_SC_PAGESIZE)");
return 1;
}
shm_fd = shm_open("/Shm", O_CREAT|O_RDWR, DEFFILEMODE);
if (shm_fd == -1) {
perror("shm_open");
return 1;
}
semsize = round_up(sizeof(sem_t), pagesize);
if (ftruncate(shm_fd, semsize) == -1) {
perror("ftruncate");
return 1;
}
sem_ptr = mmap(0, semsize, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);
if (sem_ptr == MAP_FAILED) {
perror("mmap");
return 1;
}
if (sem_init(sem_ptr, 1, 1)) {
perror("sem_init");
return 1;
}
sem_destroy(sem_ptr);
shm_unlink("/Shm");
return 0;
}
您應該注意的另一個復雜情況是,在已經初始化的信號量上調用sem_init
會導致未定義的行為。 這意味着您必須使用其他類型的鎖定來創建共享 memory 段和其中的信號量。 在我的腦海中,我不知道如何以防彈的方式做到這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.