Linux 无信号量的共享内存访问

Linux 无信号量的共享内存访问,linux,deadlock,shared,segment,Linux,Deadlock,Shared,Segment,在linux中使用共享内存API,如果我有一次写入(通过一个进程)和一次读取(通过B进程),我还需要信号量吗。?。 有没有一个例子可以说明,在linux中使用没有信号量的共享内存会进入死锁状态 没有信号量(或更普遍的互斥)就不会有死锁。然而,可能发生的是不一致/不连贯的数据 例如,如果在共享内存位置找到的对象类型是表示文本字符串的字符数组。可能一个线程开始修改字符串,另一个线程读取一次,得到一条奇怪的消息 For example: Original text "The British a

在linux中使用共享内存API,如果我有一次写入(通过一个进程)和一次读取(通过B进程),我还需要信号量吗。?。 有没有一个例子可以说明,在linux中使用没有信号量的共享内存会进入死锁状态

没有信号量(或更普遍的互斥)就不会有死锁。然而,可能发生的是不一致/不连贯的数据

例如,如果在共享内存位置找到的对象类型是表示文本字符串的字符数组。可能一个线程开始修改字符串,另一个线程读取一次,得到一条奇怪的消息

For example: Original text "The British are coming!" Thread 1 start changing to "Warn all patriots!" but only gets to write the first 8 characters. Then... Thread 2 reads "Warn allish are coming! 例如: 原文 “英国人来了!” 线程1开始更改为“警告所有爱国者!”,但只能编写 前8个字符。然后。。。 线程2读取 “阿利什来了!
编辑:参见Falaina的回复,该回复大体上与这一回复相呼应,并提供了相关概念的指针和定义:竞争条件、原子性、互斥体……

只需编写一个进程,您将无法进入死锁

然而,读者在阅读时必须能够处理部分写入的数据,这很可能是不可能的


另外,当你说一个正在写入,一个正在读取时,你真的是指只读。如果你指的是一个管道,其中一个进程将内容放在管道上,而另一个进程从管道中删除内容,那么实际上这两个进程都在写入共享内存。

当你访问共享内存时(除非你只读取)您需要防止写入期间并发写入或读取。正确的方法是使用信号量

您可以使用此ScopedLock类作为锁定机制,同时只有一个进程可以拥有具有特定名称的作用域锁。如果另一个进程将尝试创建它,它将被阻止,直到第一个进程作用域锁超出作用域

#include <semaphore.h>
class ScopedLock{
    sem_t *sem;
public:
    ScopedLock(const char* name) : sem(0)
    {
        sem = sem_open(name, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 1);
        if (sem == SEM_FAILED)
        {
            printf("Error opening semaphore : %s\n", last_error_message());
            throw "failed to create semaphore";
        }

        printf("locking interprocess lock...\n");
        if (-1 == sem_wait(sem))
        {
            printf("Error locking semaphore : %s\n", last_error_message());
            throw "failed to lock semaphore";
        }
        printf("interprocess lock locked\n");
    }

    ~ScopedLock()
    {
        if (sem)
        {
            sem_post(sem);
            printf("interprocess lock unlocked\n");
        }
    }

    // static destroy function, use for cleanup
    static void destroy(const char *name)
    {
        sem_t *sem = sem_open(name, O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
        if (sem != SEM_FAILED)
        {
            sem_post(sem);
            sem_destroy(sem);
        }

        if (-1 == sem_unlink(name))
        {
            printf("Error destroying semphore: %s\n", last_error_message());
        }
    }
};
#包括
类ScopedLock{
sem_t*sem;
公众:
ScopedLock(常量字符*名称):sem(0)
{
sem=sem|U open(名称、O|U CREAT、S|U IWUSR、S|U IRGRP、S|U IWGRP,1);
如果(sem==sem_失败)
{
printf(“打开信号量时出错:%s\n”,最后一条错误消息());
抛出“创建信号量失败”;
}
printf(“锁定进程间锁…\n”);
如果(-1==sem\u wait(sem))
{
printf(“错误锁定信号量:%s\n”,最后一条错误消息());
抛出“无法锁定信号量”;
}
printf(“进程间锁定\n”);
}
~ScopedLock()
{
if(sem)
{
sem_post(sem);
printf(“进程间锁已解锁\n”);
}
}
//静态销毁功能,用于清理
静态无效销毁(常量字符*名称)
{
sem|t*sem=sem|u open(名称,不包括S|u IRUSR | S|u IWUSR | S|u IRGRP | S|u IWGRP);
如果(sem!=sem_失败)
{
sem_post(sem);
扫描电镜(sem);
}
如果(-1==sem_unlink(名称))
{
printf(“销毁符号库时出错:%s\n”,最后一条错误消息());
}
}
};

您的问题有点奇怪。首先,您不需要使用信号量,因为还有其他同步方法

第二,不使用信号量通常不会导致死锁(除非您有一个信号量出于某种原因保护锁或其他同步方法)。使用同步方法往往会导致死锁,而不是没有死锁

但是,当编写器和读取器争夺同一资源时,您可以拥有所谓的


现在,关于一个编写器和一个读取器的问题:这可以通过互斥来完成,而不是使用信号量或任何其他数量的同步方法。或者,如果您可以保证B进程的写入是原子的(即,如果中断,它们不能使共享内存处于不一致的状态),则不需要同步。后一种情况不太可能出现,除非共享内存可以通过单个指令更新(有时甚至还不够)。您最好选择安全路径并以某种方式锁定对共享内存的访问。

这两种读/写方法是否都在同一个对象/流上运行?是否有多个进程A/进程B实例同时运行?非常感谢您的所有输入。struct sharedStruct{bool isOk;};我的要求是确保在while循环中有一个要读取的进程(isOK)和另一个要更新的进程(isOK)。在读取过程中,我对变量的任何状态(true或false)都没有问题。我甚至执行了进程B的多个副本(write isOK)看不到任何问题。只想了解需要什么额外的代码才能防止奇怪的行为(种族状况等),以及如何进入这种奇怪的状态。