Linux で共有メモリ API を使用している場合、(A プロセスによる) 書き込みが 1 つ、(B プロセスによる) 読み取りが 1 つしかない場合でも、セマフォは必要ですか? セマフォなしで共有メモリを使用すると、Linuxでデッドロック状態になる例があります。
4 に答える
セマフォ(またはより一般的にはMUTEX)がなければ、デッドロックは発生しません。ただし、発生する可能性があるのは、一貫性のない/一貫性のないデータです。
たとえば、共有メモリの場所で見つかったオブジェクトのタイプが、テキスト文字列を表すchar配列である場合です。あるスレッドが文字列の変更を開始し、別のスレッドが文字列を1回読み取って、奇妙なメッセージを受け取る可能性があります。
例えば: 元のテキスト 「イギリス人がやってくる!」 スレッド1は「すべての愛国者に警告!」に変わり始めます。しかし、書くことしかできません 最初の8文字。それで... スレッド2の読み取り 「警告の同盟国が来ています!
編集:一般的にこれを反映し、関連する概念へのポインターと定義を提供するFalainaの応答を参照してください:競合状態、原子性、ミューテックス...
あなたの質問は少し奇妙です。まず第一に、他の同期方法があるため、セマフォを使用する必要はありません。
第 2 に、セマフォを使用しないことで通常はデッドロックが発生することはありません (何らかの理由でロックまたはその他の同期方法を保護するセマフォがない限り)。同期メソッドを使用すると、デッドロックが発生する傾向がありますが、それらが存在しないためではありません。
ただし、ライターとリーダーが同じリソースに対して競合している場合、競合状態と呼ばれるものが発生する可能性があります
1 人のライターと 1 人のリーダーの質問について: これは、セマフォやその他の同期方法の代わりにミューテックスを使用して実行できます。あるいは、B プロセスの書き込みがアトミックであることを保証できる場合 (つまり、中断された場合に共有メモリを一貫性のない状態のままにすることができない場合)、同期は必要ありません。後者のシナリオは、共有メモリが 1 つの命令で更新できる場合を除き、ほとんどありません (場合によっては、それだけでは十分ではありません)。安全なルートをたどって、何らかの方法で共有メモリへのアクセスをロックする方がよいでしょう。
プロセスを1つだけ作成するだけでは、デッドロックに陥ることはありません。
ただし、リーダーは、読み取り中に部分的に書き込まれたデータを処理できる必要があります。そして、それはおそらく不可能かもしれません。
また、1つが書き込みで、もう1つが読み取りであると言うとき、それは本当に読み取り専用を意味しますか。一方のプロセスがパイプに物を置き、もう一方のプロセスがパイプから物を取り除くパイプを意味する場合、実際には両方が共有メモリに書き込んでいます。
共有メモリにアクセスするときは(読み取りのみでない限り)、同時書き込みまたは書き込み中の読み取りから保護する必要があります。これを行う適切な方法は、セマフォを使用することです。
この ScopedLock クラスをロック メカニズムとして使用できます。特定の名前のスコープ ロックを同時に所有できるプロセスは 1 つだけです。別のプロセスがそれを作成しようとすると、最初のプロセス スコープ ロックがスコープ外になるまでブロックされます。
#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());
}
}
};