5 초마다 작업을 확인하는 Windows 서비스가 있습니다. 검사 및 처리를 처리하는 데 System.Threading.Timer
을 사용하고 Monitor.TryEnter
을 사용하여 하나의 스레드 만 작업을 확인하는지 확인합니다.Monitor.TryEnter 및 Threading.Timer 경쟁 조건
다음 코드는 서비스에 의해 작성된 8 명의 다른 근로자의 일부이며 각 작업자는 확인해야하는 고유 한 특정 유형의 작업을 가지고 있으므로이 방법으로 가정해야합니다.가
위의 코드는 2 개 타이머 스레드가 CheckForWork()
방법으로 얻을 수있게된다
readonly object _workCheckLocker = new object();
public Timer PollingTimer { get; private set; }
void InitializeTimer()
{
if (PollingTimer == null)
PollingTimer = new Timer(PollingTimerCallback, null, 0, 5000);
else
PollingTimer.Change(0, 5000);
Details.TimerIsRunning = true;
}
void PollingTimerCallback(object state)
{
if (!Details.StillGettingWork)
{
if (Monitor.TryEnter(_workCheckLocker, 500))
{
try
{
CheckForWork();
}
catch (Exception ex)
{
Log.Error(EnvironmentName + " -- CheckForWork failed. " + ex);
}
finally
{
Monitor.Exit(_workCheckLocker);
Details.StillGettingWork = false;
}
}
}
else
{
Log.Standard("Continuing to get work.");
}
}
void CheckForWork()
{
Details.StillGettingWork = true;
//Hit web server to grab work.
//Log Processing
//Process Work
}
지금 여기서 문제입니다. 나는 솔직히 이것이 어떻게 가능한지 이해하지 못한다. 그러나 나는이 소프트웨어가 실행되는 여러 클라이언트에서 이것을 경험했다.
내가 오늘 작업 한 일부 로그를 보았을 때 작업을 두 번 확인했는데 독립적으로 처리하려고했던 두 개의 스레드가 있었는데 작업이 실패하여 계속 실패했습니다.
Processing 0-3978DF84-EB3E-47F4-8E78-E41E3BD0880E.xml for Update Request. - at 09/14 10:15:501255801
Stopping environments for Update request - at 09/14 10:15:501255801
Processing 0-3978DF84-EB3E-47F4-8E78-E41E3BD0880E.xml for Update Request. - at 09/14 10:15:501255801
Unloaded AppDomain - at 09/14 10:15:10:15:501255801
Stopping environments for Update request - at 09/14 10:15:501255801
AppDomain is already unloaded - at 09/14 10:15:501255801
=== Starting Update Process === - at 09/14 10:15:513756009
Downloading File X - at 09/14 10:15:525631183
Downloading File Y - at 09/14 10:15:525631183
=== Starting Update Process === - at 09/14 10:15:525787359
Downloading File X - at 09/14 10:15:525787359
Downloading File Y - at 09/14 10:15:525787359
로그는 비동기 적으로 기록되며 대기, 그래서 시간은 정확하게, 난 그냥 내가 가진 것을 보여주기 위해 내가 무엇을 로그에서 본 지적하고 싶었와 일치한다는 사실에 너무 깊이 파고하지 않습니다 2 스레드가 허용 된 적이 없어야한다고 생각하는 코드 섹션에 충돌했습니다. (로그와 시간은 실제이지만 단지 새 니타 이징 된 메시지입니다.)
결국 2 스레드는 파일에서 액세스가 거부되고 전체 업데이트가 실패하는 큰 파일을 다운로드하기 시작합니다.
어떻게 위 코드가 실제로 이것을 허용합니까? 나는 lock
을 Monitor
대신 가지고 있었고 타이머가 결국 lock
블로킹으로 인해 충분히 오프셋되기 시작했기 때문에 지난해에이 문제를 경험했습니다. 타이머가 다른 콜백을 트리거하고있는 것처럼 오른쪽을 통해 그들은 모두 어떻게 든 그것을 만들었습니다. 그래서 저는 Monitor.TryEnter
옵션을 사용하여 타이머 스태킹을 계속 스태킹하지 않을 것입니다.
단서가 있습니까? 이전에이 문제를 해결하기 위해 노력한 모든 경우에 System.Threading.Timer
은 하나의 상수였으며 그 근본 원인이라고 생각합니다.하지만 이유를 이해하지 못합니다.
'Details.StillGettingWork' (또는 그 뒷받침 필드)가'휘발성 '으로 표시됩니까? – itsme86
@ itsme86'Details'는 인스턴스 클래스이고'StillGettingWork'는 자동 속성입니다. 휘발성으로 표시된 것은 없습니다. – TyCobb
뮤텍스가 만들어진 이유는 무엇입니까? https://msdn.microsoft.com/en-us/library/windows/hardware/ff548097(v=vs.85).aspx –