Несколько процессов и ручек ожидания
Основываясь на этом вопросе, я решил попробовать использовать waithandles / eventwaithandle для моего решения, основанного на рекомендации Джима Мишеля. У меня "почти" это работает. Вот код
Private Sub InitDeploymentCheck()
moDeploymentCheck = New TRS.Deployment.TRSDeploymentCheck(EnvironmentVariables.Environment, AppDomain.CurrentDomain.BaseDirectory.Contains("bin"), MDIMain)
AddHandler moDeploymentCheck.DeploymentNeeded,
Sub()
moTimer = New System.Windows.Forms.Timer()
moTimer.Interval = 300000 '5 minutes
moTimer.Enabled = True
AddHandler moTimer.Tick,
Sub()
'check to see if the message box exist or not before throwing up a new one
'check to see if the wait handle is non signaled, which means you shouldn't display the message box
If waitHandle.WaitOne(0) Then
'set handle to nonsignaled
waitHandle.Reset()
MessageBox.Show(MDIMain, "There is a recent critical deployment, please re-deploy STAR to get latest changes.", "Critical Deployment", MessageBoxButtons.OK, MessageBoxIcon.Warning)
'set the handle to signaled
waitHandle.Set()
End If
End Sub
waitHandle.Set()
MessageBox.Show(MDIMain, "There is a recent critical deployment, please re-deploy STAR to get latest changes.", "Critical Deployment", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End Sub
End Sub
Опять же, это базовая форма, от которой наследуются практически все наши приложения. Когда мы используем одно приложение, оно отлично работает. Если вы запускаете несколько приложений, которые наследуют от базовой формы, и кто-то щелкает только одно из окон сообщения, иногда в другом приложении будет отображаться второе окно сообщения. Первоначально я ждал, что waithandle объявлен как static / shared, и подумал, что это проблема, но это не так. Я также попытался заставить каждое приложение создать свою собственную ручку ожидания и передать ее в базу, и это привело к тому же эффекту. У кого-нибудь есть идея, почему кажется, что ручка ожидания используется совместно различными приложениями? О, кстати, waitHandle на самом деле является ManualResetEvent
2 ответа
Во-первых, если вы хотите использовать это в нескольких приложениях, вам придется создать именованный EventWaitHandle
используя этот конструктор или один из других, который создает именованный объект. ManualResetEvent
будет работать только для одного процесса.
Во-вторых, названный Mutex, вероятно, является лучшим решением. Я только что понял, что код, который я рекомендовал, имеет состояние гонки. Если поток А делает WaitOne(0)
и это успешно, а затем поток B приходит и делает то же самое, прежде чем поток A может вызвать Reset
, тогда обе темы будут в конечном итоге отображать окно сообщения.
Используя Mutex
а также WaitOne(0)
решит эту проблему. Обязательно выпустите Mutex
, хоть:
if (mutex.WaitOne(0))
{
try
{
// do stuff
}
finally
{
mutex.ReleaseMutex();
}
}
Причина, по которой это не сработало правильно, в том, что у меня была ошибка, когда я показывал первое окно сообщения вне события таймера. Это должно было быть:
waitHandle.Reset()
MessageBox.Show(MDIMain, "There is a recent critical deployment, please re-deploy STAR to get latest changes.", "Critical Deployment", MessageBoxButtons.OK, MessageBoxIcon.Warning)
waitHandle.Set()