Я столкнулся с небольшими трудностями при использовании класса threadpool и массива ManualResetEvents. Ниже приведен простой пример того, что я делаю. Проблема в том, что в методе DoWork я получаю пустые ссылки на объект resetEvent [param as int].
Не могу понять, что делаю не так.
(изменить: получил рабочий блок кода)
private static volatile ManualResetEvent[] resetEvents = new ManualResetEvent[NumThreads];
public void UpdateServerData()
{
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object) i);
}
WaitHandle.WaitAll(resetEvents);
}
private void DoWork(object param)
{
//do some random work
resetEvents[(int)param].Set();
}
РЕДАКТИРОВАТЬ: я попытался вставить System.Threading.Thread.MemoryBarrier (); после каждого .Set (), однако я все еще получаю исключение с нулевой ссылкой.
3 ответа
В значительной степени я обнаружил, что проблема была в
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);
}
Вместо объявления нового события ManualResetEvent я просто вызвал Reset (). Проблема, казалось, заключалась в том, что, хотя я бы использовал MemoryBarrier или блокировки, физическая память еще не обновлялась, поэтому она указывала на null.
Вы не можете использовать ключевое слово as
для преобразования в int (поскольку int
не является ссылочным типом). Вместо этого используйте (int)param
:
private void DoWork(object param)
{
//do some random work
resetEvents[(int)param].Set();
}
Другой подход, который я считаю более чистым, - вместо этого передать методу дескриптор ожидания:
public void UpdateServerData()
{
for (int i = 0; i < NumThreads ; i++)
{
resetEvents[i] = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), resetEvents[i]);
}
WaitHandle.WaitAll(resetEvents);
}
private void DoWork(object param)
{
//do some random work
(param as ManualResetEvent).Set();
}
Таким образом, рабочий метод ничего не знает о том, как дескриптор ожидания управляется извне; и он также не может по ошибке достичь дескрипторов ожидания для других потоков.
volatile ManualResetEvent[]
не означает, что доступ к элементам массива следует изменчивой семантике. Только доступ к переменной, содержащей ссылку на массив, будет изменчивым. Попробуйте вставить барьер памяти после назначения элемента массива или используйте Thread.VolatileWrite
для их установки, например
Thread.VolatileWrite (ref resetEvents[i], new ManualResetEvent (false)) ;
Похожие вопросы
Новые вопросы
c#
C # (произносится как «резкий») - это высокоуровневый, статически типизированный язык программирования с несколькими парадигмами, разработанный Microsoft. Код C # обычно нацелен на семейство инструментов и сред выполнения Microsoft .NET, включая, среди прочего, .NET Framework, .NET Core и Xamarin. Используйте этот тег для вопросов о коде, написанном на C # или в формальной спецификации C #.
Set()
? Вам нужно увидеть обновленный элемент массива перед вызовом для негоSet()
!RegisteredWaitHandle.Unregister
после использования потока, как рекомендовано msdn, в отличие от приведенного здесь кода.