2

在linux中使用共享内存api,如果我有一个写(由A进程)而只有一个读(由B进程),我还需要信号量吗?。有没有一个例子可以说明,在没有信号量的情况下使用共享内存将在 linux 中进入死锁状态。

4

4 回答 4

3

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

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

例如:
原文
    “英国人来了!”
线程 1 开始更改为“警告所有爱国者!” 但只能写
前 8 个字符。然后...
线程 2 读取
    “警告alish来了!

编辑:请参阅 Falaina 的回应,该回应通常与这一回应相呼应,并提供相关概念的指针和定义:竞争条件、原子性、互斥体......

于 2009-10-05T15:16:01.453 回答
3

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

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

但是,当您有作者和读者竞争相同的资源时,您可以拥有所谓的竞争条件

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

于 2009-10-05T15:21:25.047 回答
0

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

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

此外,当您说一个是写作和一个阅读时,您真的是指只读吗?如果您的意思是一个管道,其中一个进程将东西放在管道上,而另一个进程从管道中删除东西,那么实际上两者都在写入共享内存。

于 2009-10-05T15:16:27.380 回答
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());
        }
    }
};
于 2009-10-05T15:19:15.627 回答