0

私はディスクリートシミュレーターで小さなエージェントベースの相互作用シミュレーションを書いていて、次のようなコードを書き始めています。私はこれまでイベント駆動型プログラミングを行ったことがありませんが、この状況を実際に観察していませんでした。次のコードは、の値を更新しているときに競合状態につながるのではないかと思いますmsgRcvd

// Following is the event-loop per-se
Controller {
    if (...) {
       SendMessage(currentTime() + 5, i,j)
       SendMessage(currentTime() + 5, i,k)
    }
    print currentTime(), msgsRcvd
    Schedule(currentTime()+1, Controller)
}

// The following function is called when an 
// agent receives a message
Receive(Agent agent) {
    if (...) {
       msgsRcvd++ // <-- this is a global variable
    }
}

私の理解では、両方のイベントが同時に論理的に発生しているため、currentTime() + 5両方のエージェントが同時にメッセージを受信するため、メッセージの数は2になるはずです。または、奇妙な競合状態が発生し、値がスケジューラーに依存しているのがわかりますか(つまり、1または2を出力する可能性があります)?助言がありますか?

4

3 に答える 3

1

答えは、イベントトランスポートの実装によって異なり、その意味で言語に依存しません。

私が使用したすべてのシステムでは、各メッセージは個別にイベントキューに配置され、受信エージェントはそのキューからイベントを順番に削除します。メッセージを生成するスレッドが1つあり、メッセージをキューから削除するイベントが1つあるとすると、競合状態になる可能性はありません。

イベントキューにタイムスタンプに基づいてイベントを統合しようとするインテリジェンスがある場合、受信エージェントには1つのイベントしか表示されません。私はそれを行う一般的なシステムを知りません(たとえば、一部のUIシステムは2回の高速マウスクリックをダブルクリックに統合する場合があります...しかし、それは特定のイベントシステムの特定の動作であり、言語/プラットフォームに依存しません)。

于 2011-10-04T22:39:05.587 に答える
1

いいえ、エージェントコードは非常に疑わしく、危険に見えますが、この場合、競合状態が発生することはわかりません。msgsRcvdは常に正しい合計になるはずです。スケジューラーが増分の直前にagent1に割り込んだとしても、その増分を完了するために常に制御が戻ってくるように思われます。コントローラが制御を取得した場合、MsgsRcvdの不正確な内容が報告される可能性がありますが、それではどうでしょうか。MsgsRcvdはすぐにフェーズに戻ります。

ただし、これは確かに恐ろしいコードです。この種のコードを見ているときは、常にMsgsRcvdの増分をコントローラーに移動して、増分を実行する関数を公開したいと思います。しかし、それは私がこの場合気分が良くなるだけです。ロジックを変更せず、MsgsRcvdが一時的に不正確になるという「問題」(ある場合)を解決することもありません。

于 2011-10-04T22:43:48.840 に答える
1

もともと、この質問に答える言語/プラットフォームにとらわれない方法はないと言及するつもりでしたが、EricJ.がそれをカバーしています。

C ++では、コールバックがシリアル化されることがプラットフォームで保証されていない限り、記述されたコードは安全ではありません。その理由は、インクリメント演算子がアトミックではなく、2つのスレッドが同時に値を更新しようとしている場合、フェッチ、追加、および保存の順序に応じて、さまざまなことが発生する可能性があるためです。

このプラットフォームが本当に並行性を念頭に置いて設計されている場合は、必要な機能を提供する「インターロック/アトミック」APIが必要です。

于 2011-10-04T22:45:17.867 に答える