У меня есть 5 потоков, которые пытаются ввести критический раздел статического класса в произвольное время. Если другой поток находится в критическом разделе, я хочу, чтобы остальные "отступили" и попытались в более позднее время. Проблема заключается в том, что кажется, что блокировка не освобождается после того, как первый поток входит в критический раздел, потому что остальные false всегда будут возвращены, если "точка останова" в Monitor.TryEnter(thisLock)
. Любая помощь будет оценена по достоинству. Благодарю.
Это мой код:
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
Monitor.Enter(thisLock);
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
Легально, чтобы тот же поток вызывал Enter более одного раза без его блокировки; однако необходимо вызывать равное количество вызовов выхода, прежде чем другие потоки, ожидающие на объекте, будут разблокированы.
http://msdn.microsoft.com/en-us/library/de0542zz%28v=vs.110%29.aspx
В принципе, вы приобретаете блокировку два раза в своем коде. Вам необходимо удалить вызов Monitor.Enter
так как Monitor.TryEnter
уже приобрел блокировку.
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
Вы приобретаете блокировки дважды, но только один раз отпускаете его.
Если TryEnter
успешным, вы получите блокировку. Это означает, что вам не нужно явно получать его снова. Однако вам нужно его явно освободить. Таким образом, ваш код должен выглядеть так:
static class Receiver
{
public static object thisLock = new object();
public static int success;
public static bool hasLocked()
{
if(Monitor.TryEnter(thisLock))
{
System.Threading.Thread.Sleep(10);
success++;
Monitor.Exit(thisLock);
return true;
}
return false;
}
}
Мониторы являются ретерантами, поэтому их можно приобрести несколько раз. Однако вы должны помнить о том, чтобы освободить их на тот же номер, иначе они останутся заблокированными.
Monitor.TryEnter(thisLock)
блокировку дваждыMonitor.TryEnter(thisLock)
затем сноваMonitor.Enter(thisLock)
, ноMonitor.Enter(thisLock)
только один раз.