簡體   English   中英

如何將未命名的 Posix 信號量寫入共享 Memory?

[英]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_waitsem_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM