これは .net Monitor/lock ステートメントのバグですか、それとも MessageBox.Show の動作が異なるのでしょうか?
質問
win フォームに 2 つのボタンがあると想像してください。ユーザーが以下のコードで「ボタン 1」を押したときの動作はどうあるべきだと思いますか?
5 つのメッセージ ボックスをすべて一度に表示するか、それとも 1 つずつ表示する必要がありますか (MessageBox.Show ステートメントは lock ステートメント内にあります)。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static readonly object lockobject = new object();
private void button1_Click(object sender, EventArgs e)
{
var action = new Action(function);
for(int i = 0; i< 5; i++)
{
action.BeginInvoke(null, null);
}
}
private void function()
{
if (button2.InvokeRequired)
{
var func = new Action(function);
button2.Invoke(func);
}
else
{
lock (lockobject)
{
MessageBox.Show("Testing");
}
}
}
}
ここで、MessageBox.Show を他のステートメントに置き換えると、そのステートメントは一度に 1 つだけ実行され、他のスレッドは一度に 1 つずつ待機します。
解決
、ロックはすべて同じ(メイン)スレッド上で実行されます。したがって、ロックはブロックしません。
あなたがメッセージボックスをブロックする場合は、代わりにShowDialogを使用しています。
他のヒント
lock は、別のスレッドがロックを所有している場合にのみブロックし、同じスレッドから同じオブジェクトを複数回ロックすることが許可されます。そうでない場合は、現在のスレッドを待機している間に現在のスレッドをブロックすることになるため、即座にデッドロックになります。
Control.BeginInvoke は、別のスレッドでコードを実行しません。常に、コントロールのメッセージをポンプするスレッドでコードを実行します。これは、コントロールの入力キューにメッセージをポストし、メッセージが到着したときにコードを実行することによって実行されます。
2 のため、コードはまったくマルチスレッドではなく、すべてが同じスレッドで実行されます。これで 1 に戻ります。複数のスレッドがない場合、ロックは何も行われません。
私は、UIスレッドがメッセージボックスのライフサイクル中にメッセージをポンプが疑われます。ロックがリエントラントである(およびUIスレッドがコードを毎回実行している)ので、これは、上記の原因となります。 おそらく、メッセージボックスに所有者(。this
)を通過してみてください? (私は...秒でみます)
あなたはより力強く、それをブロックすることができ、それは絵(など「応答なし」)をブロックします。
私はニールに同意します。あなたは、以下のいずれかにあなたの関数を変更した後、あなたは同じスレッド上で実行されていることをテストすることができます(当然ながら):
private void function()
{
if (button2.InvokeRequired)
{
var func = new Action(function);
button2.Invoke(func);
}
else
{
lock (lockobject)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
MessageBox.Show("Testing. Running on thread "+threadId);
}
}
}
あなたのUIスレッドがロックを起因しているので、だからここに、それはブロックされません。ボトムラインは、STAスレッドが適切なマルチスレッドプログラミングと互換性がないということである。