【问题标题】:sem_wait is ignored in my programsem_wait 在我的程序中被忽略
【发布时间】:2014-01-09 02:13:24
【问题描述】:

我在 linux 中写了一个关于共享内存的简单项目。两个程序共享内存,一个是给它写信,第二个是从中读取它们。我决定使用信号量来确保在读取之前不会产生新的字母。

问题是我的 writer 进程在 sem_wait(reading) 的值为 0 时忽略了它,它应该等待。它甚至在读者开始之前就完成了它的工作。我通过./writer & ./reader 运行它。

我附上代码。这里有一些未使用的元素,因为它还不是最终版本。但是问题已经出现了。

/* writer.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>

int main( int argc, char *argv[] )
{
    key_t shmkey = 0xF00;
    int bytes = sizeof(char)*3 + sizeof(sem_t) * 3;
    int shmid;
    char* sharedMemory;
    sem_t *writing, *reading, *working;

    if ( (shmid = shmget( shmkey, bytes, IPC_CREAT | IPC_EXCL | 0666 )) < 0 )
    {
        shmdt( (void*) sharedMemory );
        shmctl( shmid, IPC_RMID, NULL );
        return 1;
    }
    if ( (sharedMemory = (char*) shmat( shmid, NULL, 0 )) == (char*) -1 )
    {
        shmdt( (void*) sharedMemory );
        shmctl( shmid, IPC_RMID, NULL );
        return 1;
    }

    writing = (sem_t*)(sharedMemory + 3);
    reading = writing + 1;
    working = reading + 1;

    sem_init( writing, 0, 0 );
    sem_init( reading, 0, 0 );

    sharedMemory[2] = 'w'; // writer is running
    char c;
    for( c = 'a'; c <= 'z'; ++c )
    {
        *sharedMemory = c;
        sem_post( writing );
        sem_wait( reading );
    }
    sharedMemory[2] = 'q';
    while ( sharedMemory[2] != 'w' );
    sharedMemory[2] = 'q';
    shmdt( (void*) sharedMemory );
    shmctl( shmid, IPC_RMID, NULL );
    return 0;
}

还有读者,

/* reader.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>

int main( int argc, char *argv[] )
{
    key_t shmkey = 0xF00;
    int bytes = sizeof(char)*3 + sizeof(sem_t) * 3;
    int shmid; 
    char* sharedMemory;
    sem_t *writing, *reading, *working;

    sleep(1); // wait until writer allocates fresh memory
    if ( (shmid = shmget( shmkey, bytes, 0666 )) < 0 )
    {
        shmdt( (void*) sharedMemory );
        return 1;
    }
    if ( (sharedMemory = (char*) shmat( shmid, NULL, 0 )) == (char*) -1 )
    {
        shmdt( (void*) sharedMemory );
        return 1;
    }

    if ( sharedMemory[2] != 'w' ) // is writer running?
    {
        shmdt( (void*) sharedMemory );
        return 1;
    }

    writing = (sem_t*)(sharedMemory + 3);
    reading = writing + 1;
    working = reading + 1;

    //sleep(5); //@REMOVE

    char c;
    do
    {
        sem_wait( writing );
        c = *sharedMemory;
        sem_post( reading );
        printf( "%c\n", c );
    } while ( sharedMemory[2] == 'w' ); 
    sharedMemory[2] = 'w';
    shmdt( (void*) sharedMemory );
    return 0;
}

【问题讨论】:

  • 文档说 sem_init() 的第二个参数应该是非零的,以便在进程之间共享信号量 - 您似乎正在调用未定义的行为。如果你改变它会发生什么?
  • @Notlikethat 它没有帮助
  • 您还应该检查返回值 - 失败时读取 errno 会告诉您出了什么问题。
  • @woolstar 我不知道。我以前使用过信号量,但没有那个过程,虽然没有共享内存。您能否给我一个提示该命令的外观,即我应该设置哪些标志以及代码末尾的 destroy() 是否足以释放它的内存?
  • 对不起,您使用的样式称为未命名信号量,我很熟悉,但基本上是有效的。

标签: c linux semaphore shared-memory


【解决方案1】:

sharedMemory + 3 未正确对齐 sem_t 类型。由于您不知道 sem_t 的对齐要求,因此您需要确保您的 sem_t 对象从共享内存段中的偏移量开始,该偏移量是 sizeof(sem_t) 的倍数(这是因为对齐要求任何对象均分其大小)。

请注意,您应该检查sem_waitsem_post 的返回值。然后,您可以检查 errno 是否失败,这将为您提供有关失败原因的信息(但在您的情况下,我怀疑 errno 值可能没有帮助)。

【讨论】:

  • 我正在检查它们。它们等于 0。所以看起来 sem_init() 有效。
  • 我不明白为什么要检查 errno。 Writer 进程结束并返回 0,所以从程序的角度来看应该不会有任何错误,对吗?
  • 我更改了bytes = sizeof(sem_t)*4,据我了解,它创建了所需的偏移量。它没有帮助。
  • 这不是我建议的更改。我说你应该把前 3 (那个乘以sizeof(char),顺便说一句,写 1 的方式很丑)和sharedMemory + 3 中的 3 都改成sizeof(sem_t)
  • 至于检查错误返回和检查errno,它不一定有助于找到您的错误,因为您正在调用未定义的行为。但一般来说,sem_postsem_wait 可能会失败(尤其是 sem_wait 在被信号中断时可能会因EINTR 而失败),因此您应该检查它们的返回值,而不是假设它们成功了。在您的情况下,我怀疑 sem_wait 正在从内核获取 EINVALEFAULT 或其他内容,以传递无效(未对齐)地址以等待。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 2016-11-26
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
  • 2015-02-02
相关资源
最近更新 更多