Если есть несколько потоков, ожидающих одной и той же блокировки, возможно ли, чтобы основной поток имел более высокий приоритет при получении блокировки. Это означает, что если рабочие потоки переходят к оператору lock
перед основным потоком, основной поток получит блокировку раньше других потоков, которые уже ожидают его.
С# можно ли изменить приоритет получения блокировки?
Ответы:
Нет, оператор lock
сопоставляется с System.Threading.Monitor.Enter()
(MSDN), и нет перегрузка, которая принимает параметр приоритета.
Самое близкое, что я могу придумать, это ReaderWriterLock(Slim), но я бы серьезно пересмотрел дизайн, который приводит к этому запросу. Вероятно, есть лучшие способы добиться того, что вам нужно.
Через собственный оператор блокировки, нет. С помощью вашего собственного механизма блокировки, конечно, если вы готовы потратить время и усилия на его разработку.
Вот мой проект решения. Это может работать или не работать, и может быть не очень эффективным, но это, по крайней мере, отправная точка:
public class Lock
{
bool locked = false;
private object key = new object();
SortedDictionary<int, Queue<ManualResetEvent>> notifiers =
new SortedDictionary<int, Queue<ManualResetEvent>>();
ManualResetEvent specialNotifier = null;
public void Lock()
{
lock (key)
{
if (locked)
{
ManualResetEvent notifier = new ManualResetEvent(false);
int priority = getPriorityForThread();
Queue<ManualResetEvent> queue = notifiers[priority];
if (queue == null)
{
queue = new Queue<ManualResetEvent>();
notifiers[priority] = queue;
}
queue.Enqueue(notifier);
notifier.WaitOne();
}
else
{
locked = true;
}
}
}
private static int getPriorityForThread()
{
return 0;
}
public void Release()
{
lock (key)
{
foreach (var queue in notifiers.Values)
{
if (queue.Any())
{
var notifier = queue.Dequeue();
notifier.Set();
return;
}
}
locked = false;
}
}
}
Вот еще одно решение. У меня много строк, но это довольно просто. Функция DoSomethingSingle
будет вызываться только по одному потоку за раз, и те, у кого установлен флаг highPriority
, получат преимущество.
static int numWaiting = 0;
static object single = new object();
ResultType DoSomething(string[] argList, bool highPriority = false)
{
try
{
if (highPriority)
{
Interlocked.Increment(ref numWaiting);
}
for (;;)
{
lock (single)
{
if (highPriority || numWaiting == 0)
{
return DoSomethingSingle(argList);
}
}
// Sleep gives other threads a chance to enter the lock
Thread.Sleep(0);
}
}
finally
{
if (highPriority)
{
Interlocked.Decrement(ref numWaiting);
}
}
}
Это позволяет использовать два уровня приоритета. Гарантируется, что поток с низким приоритетом получит доступ к ресурсу только в том случае, если его не ожидают потоки с высоким приоритетом.
изменить: изменить на блокировку incr/dec