没有信号量的共享内存访问

时间:2009-10-05 15:06:56

标签: linux deadlock shared segment

在linux中使用共享内存apis,如果我有一次写入(通过A进程)并且只有一次读取(通过B进程),我仍然需要信号量。?. 有没有一个例子可以显示,使用没有信号量的共享内存会在linux中进入死锁状态。

4 个答案:

答案 0 :(得分:3)

没有信号量(或者更常见的是MUTEX),就不会出现死锁。然而,可能发生的是不一致/不连贯的数据。

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

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!

编辑:请参阅Falaina的回复,该反应通常与此相关,并提供相关概念的指示和定义:竞争条件,原子性,互斥...

答案 1 :(得分:3)

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

其次,不使用信号量通常不会导致死锁(除非您因某种原因有信号量保护锁或其他同步方法)。同步方法的使用往往导致死锁,而不是缺失。

但是,当您有作者和读者争夺同一资源时,您可以拥有所谓的Race Condition

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

答案 2 :(得分:0)

只有一个进程写入,你将无法陷入死锁。

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

另外,当你说一个人正在写作和一个阅读时,你的意思是只读。如果你指的是一个管道,一个进程将东西放在管道上,另一个进程从管道中删除东西,那么两个都正在写入共享内存。

答案 3 :(得分:0)

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

您可以使用此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());
        }
    }
};