Cで関数をアトミックにする方法はありますか.
移植可能なソリューションは探していません (探しているプラットフォーム - Win、Linux)
多分。
「アトミック」の定義に完全に依存します。
オペレーティング システムが関与しないシングル コアの深く組み込まれた環境では、通常、割り込みを無効にしたり有効にしたりできます。これを使用して、割り込みハンドラー コードに対して関数をアトミックにすることができます。ただし、マルチマスター バス、DMA エンジン、またはメモリを個別に書き込むことができるその他のハードウェア デバイスがある場合は、状況によっては、割り込みをマスクしても十分な保証が得られないことがあります。
RTOS (リアルタイム オペレーティング システム) 環境では、OS カーネルは通常、クリティカル セクションなどの低レベルの同期プリミティブを提供します。クリティカル セクションは、少なくとも他のすべてのクリティカル セクションに関して、「本質的に」原子的に動作するコードのブロックです。これは通常、OS の他の同期プリミティブの実装の基本です。
マルチコア環境では、スピンロックと呼ばれる低レベルのプリミティブが利用できることがよくあります。これは、同じスピンロック オブジェクトの他のユーザーに対してアトミックである必要があるコード ブロックへのエントリを保護するために使用され、ロックが解放されるまで待機中の CPU コアをタイト ループでブロックすることによって動作します (名前の由来)。
多くのスレッド環境では、イベント、セマフォ、ミューテックス、キューなどのより複雑なプリミティブがスレッド フレームワークによって提供されます。これらはスレッドスケジューラと連携して、何かが起こるのを待っているスレッドが条件が満たされるまでまったく実行されないようにします。これらを使用して、同じ同期オブジェクトを共有する他のスレッドに対して関数のアクションをアトミックにすることができます。
一般的なルールは、タスクに適した環境で利用可能な最高レベルの機能を使用することです。最良の場合、メッセージ キューなどの既存のスレッド セーフ オブジェクトを使用して、コード内で特別なことをまったく行う必要がないようにすることができます。
関数がシグナルによって中断されないようにしたい場合は、 を使用sigprocmask()
してシグナルをマスクおよびマスク解除しますが、一部のシグナルはブロックできず ( などSIGKILL
)、一部のシグナルをブロックする場合の動作 ( などSIGSEGV
) は定義されていません。
詳細man sigprocmask
については、を参照してください。
「アトミック」の意味を定義します。関数を実行するときに他のプロセスやスレッドがスケジューリングに選択されないという意味で、「アトミック」を意味しますか?または、関数の実行中に、関数で参照されている共有オブジェクトが他のスレッドによって変更されないことを意味しますか?
前者の場合、ユーザースペースからそれを実際に制御することはできません。シングルCPUマシンを使用している場合は、プロセスの優先度を(ユーザースペースから)可能な限り高い優先度に上げることで、アトミック性を保証できる可能性があります。ただし、それでも、スケジューリングアルゴリズムによって別のプロセスの実行が許可される可能性があるため、保証されません。これを行う唯一の信頼できる方法は、オペレーティングシステムからです。シングルCPUマシンの場合、割り込みを無効にします。マルチコアマシンの場合、バスをロックし、他のCPUで実行されているすべてのプロセスが削除されるのを待つ必要があります。
ここでの問題は、なぜ原子性を保証したいのかということです。一般に、プロセスのみが実行され、他のプロセスは実行されないという要件は、ユーザースペースに存在してはなりません。特定のデータ構造に一度に1つのスレッドだけがアクセスできるようにする場合は、ポータブルスレッドライブラリ(pthread
たとえば)を使用し、クリティカルセクションとしての機能を隔離する必要があります。
少なくともポータブルではありません。一部のシステムでは、カーネルが機能を横取りするのを防ぐために、マシンの割り込みを切り替えるなどの方法で、おそらくそれにアプローチできます。しかし、特に非組み込みシステムの場合、それは非常に困難です。
これを行うには、ハードウェア命令用の特別なコンパイラ組み込み関数を使用するか、オペレーティング システムのサポートを使用して、プラットフォーム固有のサポートが必要です。C も C++ も同期機能を標準化していません。
アトミックとは、「一度に 1 つのスレッドのみ」を意味する場合、(Windows では) クリティカル セクション ブロックを使用して関数を保護することができます。Linux では、mutex のロック/ロック解除を使用して、クリティカル セクションを多かれ少なかれエミュレートします。
Windows と Linux の両方で動作する可能性のある POSIX セマフォやミューテックスなどを調べることをお勧めします。
たとえば cygwin や minGW を使用すると、Linux と Windows の間で移植可能なコードを作成することさえ可能です。
Linux で Windows ライブラリを作成することもできます: http://cdtdoug.blogspot.com/2009/05/mingw-cross-for-linux.html