好奇心から、Linux でプロセス間同期を実現するための推奨される方法は何ですか? sem*(2)
ファイルをロックするにはfcntl()
、flock()
とlockf()
.
内部の違いは何ですか (ある場合)、それぞれの使用をどのように正当化しますか?
好奇心から、Linux でプロセス間同期を実現するための推奨される方法は何ですか? sem*(2)
ファイルをロックするにはfcntl()
、flock()
とlockf()
.
内部の違いは何ですか (ある場合)、それぞれの使用をどのように正当化しますか?
ない。pthread_*
(例: )の実際のバージョンはphtread_mutex_t
すべて、 を介して作成された共有セグメントに変数を配置できshm_open
ます。init 呼び出しに追加のパラメーターを配置するだけです。
必要がない場合は、セマフォ ( sem_t
) を使用しないでください。セマフォはレベルが低すぎて、IO などによって中断されます。
プロセス間制御のためにファイル ロックを悪用しないでください。そのために作られているわけではありません。特に、ロックなどのファイル メタデータをフラッシュする可能性がないため、ロック/ロック解除がいつ 2 番目のプロセスから見えるようになるかわかりません。
DarkDustが指摘したように、あなたは豊かな歴史からの豊富な選択に苦しんでいます. 私の決定木は次のようになります。
一度に 1 つのプロセス/スレッドしかアクセスできない場合は、ミューテックスを使用します。
2 つ以上の (ただし有限の) プロセス/スレッドがリソースを使用できる場合は、セマフォを使用します。
SYSV セマフォが持っている何かが本当に必要でない限り、POSIX セマフォを使用してください - 例えば、UNDO、最後の操作の PID など。
ファイルに対してファイル ロックを使用するか、上記が要件に何らかの形で合わない場合に使用します。
さまざまなロック/セマフォの実装はすべて、さまざまなシステムで実現しました。System V Unixではsemget
/semop
があり、POSIX は , と で別の実装を定義しsem_init
ましsem_wait
たsem_post
。そしてflock
、私が知る限り、4.2BSD に由来します。
それらはすべて特定の重要性を獲得したため、Linux は移植を容易にするためにそれらすべてをサポートしています。また、flock
ミューテックス (ロックまたはロック解除) ですが、sem*
関数 (SysV と POSIX の両方) はセマフォです。アプリケーションは複数の同時プロセス アクセスを許可できます。たとえば、リソースへのアクセスをセマフォで同時に 4 つのプロセスに許可できます。セマフォを使用してミューテックスを実装することはできますが、その逆はできません。Marc J. Rochkind による優れた"Advanced UNIX Programming"で、彼はセマフォを介してプロセス間でデータを送信する方法を実演したことを覚えています (非常に非効率的です。彼はそれが可能であることを証明するためだけにそれを行いました)。しかし、効率について信頼できるものは何も見つかりませんでした。
「使いたいものを使う」のほうがいいと思います。
潜在的に重要な違いは、リソース配分の公平性です。ファミリの実装の詳細はわかりませんが、semget/semop
スケジューリングに関する限り、通常は「従来の」セマフォとして実装されているのではないかと思います。一般に、解放されたスレッドは FIFO ベースで処理されると思います (セマフォを待っている最初のスレッドが最初に解放されます)。処理がカーネル レベルで実行されていないのではないかと思うので (これも推測ですが)、ファイル ロックでこれが起こるとは思いません。
IPC の目的でセマフォをテストするための既存のコードが手元にあったので、2 つの状況 (1 つは を使用しsemop
、もう 1 つは を使用lockf
) を比較しました。私は貧しい人のテストを行い、アプリケーションのインスタンスを実行しました。開始を同期するために共有セマフォが使用されました。semop テストを実行すると、両方のプロセスがほぼ同期して 300 万回のループを完了しました。一方、lockf ループはそれほど公平ではありませんでした。通常、1 つのプロセスは終了し、もう 1 つのプロセスはループの半分しか完了していませんでした。
semop テストのループは次のようになります。semwait
および関数は、呼び出しのsemsignal
単なるラッパーです。semop
ct = myclock();
for ( i = 0; i < loops; i++ )
{
ret = semwait( "test", semid, 0 );
if ( ret < 0 ) { perror( "semwait" ); break; }
if (( i & 0x7f ) == 0x7f )
printf( "\r%d%%", (int)(i * 100.0 / loops ));
ret = semsignal( semid, 0 );
if ( ret < 0 ) { perror( "semsignal" ); break; }
}
printf( "\nsemop time: %d ms\n", myclock() - ct );
両方の方法の合計実行時間はほぼ同じでしたが、スケジューリングの不公平が原因で、実際には lockf バージョンの方が全体的に高速でした。最初のプロセスが完了すると、もう一方のプロセスは約 150 万回の反復で競合することなくアクセスでき、非常に高速に実行されます。
競合なしで実行した場合 (単一プロセスがロックを取得して解放した場合)、semop バージョンの方が高速でした。100 万回の反復で約 2 秒かかりましたが、lockf バージョンでは約 3 秒かかりました。
これは、次のバージョンで実行されました。
[]$ uname -r
2.6.11-1.1369_FC4smp