Могу ли я использовать блокировку с этим ManualResetEvent для обеспечения безопасности потока? - PullRequest
0 голосов
/ 13 июня 2019

Скажем, у меня есть две функции, которые управляют счетчиком, и функция OnTimer, которая срабатывает через регулярный интервал.

void IncrementCount()
{
    _myCount++;
}

void OverwriteCount(int newValue)
{
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
}

Я хочу, чтобы, если / когда вызывается OverwriteCount, IncrementCount не может быть выполненпока функция таймера не будет выполнена.

Моя первоначальная мысль для решения этой проблемы заключалась в том, чтобы использовать ManualResetEvent для синхронизации действий:

private static ManualResetEventSlim mre = new ManualResetEventSlim(initialState: true);

void IncrementCount()
{
    mre.Wait(-1); // can't increment until the event is signaled
    _myCount++;
}

void OverwriteCount(int newValue)
{
    mre.Reset(); // unsignal the event, blocking threads
    _myCount = newValue;
}

void OnTimer()
{
    Console.WriteLine(_myCount);
    mre.Set(); // signal the event
}

Моя задача - вырожденный многопоточный сценарий, в котором поток Aпроходит мимо mre.Wait () в IncrementCount (), но на самом деле еще не увеличил _myCount.Затем поток B вызывает mre.Reset () и перезаписывает _myCount.Затем поток A получает поворот и увеличивает значение _myCount.

Могу ли я решить эту проблему, добавив блокировку в IncrementCount () и OverwriteCount (), чтобы гарантировать, что только один поток может изменять _myCount одновременно?Могу ли я зайти в тупик, если застрял в ожидании события сброса, удерживая блокировку?

1 Ответ

1 голос
/ 13 июня 2019

Если я вас понимаю, тогда да, это сработает, если вы выберете то, что нужно заблокировать соответствующим образом. Возможно, есть более детальный способ сделать это, но на данный момент я не вижу ничего плохого в этом

void IncrementCount()
{
   mre.Wait();

   // lets not cause a race, lock until OverwriteCount is finished
   lock (_sync)
   {
      _myCount++;
   }
}

void OverwriteCount(int newValue)
{
   // lock this so we can assure the count is updated
   lock (_sync)
   {
      mre.Reset(); // unsignal the event, blocking threads
      _myCount = newValue;
   }
}

void OnTimer()
{
   Console.WriteLine(_myCount);
   mre.Set(); // signal the event
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...