これはインタビューの質問です。
Linux/UNIXのマルチプロセッシングケースでミューテックスを使用することは可能ですか?
私の考え:いいえ、異なるプロセスには別々のメモリ空間があります。
mutexはマルチスレッドにのみ使用されます。
セマフォは、同期を行うマルチプロセッシングに使用されます。
正しい ?
コメントを歓迎します。
ありがとう
Mutual exclusion locks (mutexes) prevent multiple threads
from simultaneously executing critical sections of code that
access shared data (that is, mutexes are used to serialize
the execution of threads). All mutexes must be global. A
successful call for a mutex lock by way of mutex_lock()
will cause another thread that is also trying to lock the
same mutex to block until the owner thread unlocks it by way
of mutex_unlock(). Threads within the same process or
within other processes can share mutexes.
Mutexes can synchronize threads within the **same process** or
in ***other processes***. Mutexes can be used to synchronize
threads between processes if the mutexes are allocated in
writable memory and shared among the cooperating processes
(see mmap(2)), and have been initialized for this task.
初期化ミューテックスは、そのミューテックスの初期化に暗黙的または明示的に渡される引数に応じて、プロセス内またはプロセス間です。静的に割り当てられたミューテックスは、明示的に初期化する必要はありません。デフォルトでは、静的に割り当てられたミューテックスはすべてゼロで初期化され、そのスコープは呼び出しプロセス内に設定されます。
For inter-process synchronization, a mutex needs to be allo-
cated in memory shared between these processes. Since the
memory for such a mutex must be allocated dynamically, the
mutex needs to be explicitly initialized using mutex_init().
process-shared mutex を使用することはかなり可能です。
実際、最新のアプリケーションでは、セマフォの柔軟性が低いため、プロセス共有ミューテックスとプロセス共有条件変数を使用することを好みます。
2004年にRed Hat Linuxを使用したことを覚えていますが、当時はプロセス共有ミューテックスと条件変数の両方をサポートしていました。
そうでもない。 POSIXスレッドには process-shared attribute という概念があり、これを使用して、複数のプロセスで操作できるmutexを作成できます。
このようなミューテックスを共有メモリに配置して、複数のプロセスがすべて取得できるようにすることができます。
LINUXがこれを実装しているかどうかはわかりませんが、不必要に複雑に見えるため、使用する必要がありませんでした。
属性の有用な精度については、 この質問 への私の答えを参照してください。
プロセスの存続期間にわたって相互排除を保証できるように、名前付きミューテックスを探していました(特定のプロパティセットごとに1つのプロセスのみが実行されるようにします)。私はそれを見つけませんでした(十分に見えなかったように見えます)。そのため、抽象UNIXドメインソケットを使用して、Linuxに独自の疑似名前付きミューテックスを実装しました。そのソケットへの単一のbind()のみが成功します。もう1つの良い点は、プロセスが停止し、ソケット自体をクリーンアップしない場合、OSが抽象UNIXドメインソケットをクリーンアップすることです。残念ながら、この擬似ミューテックスが使用可能になるまで「待機」する方法はわかりません。
抽象UNIXドメインソケットは、名前がヌルバイトで始まるUNIXドメインソケットです。ただし、バッファ全体が名前として使用されるため、memcpyやstrcpyに部分的な文字列を入れないようにするか、最初にバッファ全体を何らかの文字で埋めるようにする必要があることに注意してください。
最初のbind()以外はすべて、EADDRINUSEのerrnoで失敗します。
// Create an abstract socket to use as a mutex.
int err;
int mutex_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (mutex_sock == -1)
{
err = errno;
printf("main, failed creating mutex socket: %s\n",
get_error_string(errno, error_string, sizeof(error_string)));
log_event(LOG_LEVEL_ERROR, "main, failed creating mutex socket: "
"%s", get_error_string(errno, error_string,
sizeof(error_string)));
errno = err;
goto done;
}
// Bind to abstract socket. We use this as a sort of named mutex.
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.Sun_family = AF_UNIX;
strncpy(addr.Sun_path + 1, socket_name, sizeof(addr.Sun_path) - 2);
result = bind(mutex_sock, (struct sockaddr*) &addr, sizeof(addr));
if (result == -1)
{
err = errno;
if (errno == EADDRINUSE)
{
printf("main, failed bind to mutex socket: %s. "
"Another instance must be running.\n",
get_error_string(errno,
error_string, sizeof(error_string)));
log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: "
"%s. "
"Another instance must be running.",
get_error_string(errno,
error_string, sizeof(error_string)));
}
else
{
printf("main, failed bind to mutex socket: %s\n",
get_error_string(errno, error_string,
sizeof(error_string)));
log_event(LOG_LEVEL_ERROR, "main, failed bind to mutex socket: %s",
get_error_string(errno, error_string,
sizeof(error_string)));
}
errno = err;
goto done;
}
ありがとう、ニック
はい、Linuxでは一般に、名前のないミューテックスしかありません。これは、プロセス間で動作できないためです。それを乗り越えるにはセマフォが必要です。
Windowsでは、名前付きミューテックスの概念があり、プロセス間でミューテックスを使用できます。