Избегать повторяющихся вызовов подпрограммы из нескольких потоков в win-форме?

#c# #.net #winforms #multithreading

#c# #.net #winforms #многопоточность

Вопрос:

У меня есть частная объектная переменная в форме Windows, которая выполняет соединение с сокетом tcp / IP и сохраняет соединение открытым.

При form_load этот объект инициализируется, и в форме непрерывно выполняется 15-20 потоков, которые обращаются к этому объекту. Существуют сценарии, в которых соединение Tcp / Ip может быть потеряно. ПОЭТОМУ всякий раз, когда я обнаруживаю, что соединение потеряно, я вызываю метод ReconnectToSocket() в потоке. Я выполняю приведенный ниже код, чтобы убедиться, что метод ReconnectToSocket() вызывается только один раз с помощью свойства _ReconnectingSocket . Но после проверки файлов текстовых журналов я обнаружил, что этот метод вызывается в каждом подпотоке.

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

Ниже приведен мой код. Меня интересует любой альтернативный подход, потому что я чувствую, что это неправильный подход при этом.

     bool _bReconnectingSocket = false;//To check if it is currently reconnecting
    readonly object lock_reconnectSocket = new object();
    private bool _ReconnectingSocket
    {
        get
        {
            lock (lock_reconnectSocket)
            {
                return this._bReconnectingSocket;
            }
        }
        set
        {
            lock (lock_reconnectSocket)
            {
                this._bReconnectingSocket = value;
            }
        }
    }


    private void ReconnectToSocket()
    {
        if (!this._ReconnectingSocket)
        {
            this._ReconnectingSocket = true;

            //Each sub thread checks for this variable while looping and exits from the infinite loop
            this._Stop = true;

            //Join all the Sub Threads Before Reconnecting
            foreach (SocketThread thrd in this._subThreadCol)
            {
                try
                {
                    this._objLog.WriteInfo(string.Format("Joining Subthread - {0} for Reconnecting.", thrd.ThrdID));
                    thrd.Join();
                }
                catch { }
            }

            this.ConnectSocket();

            this._ReconnectingSocket = false;
            this._Stop = false;
        }
    }
  

Комментарии:

1. Это выглядит очень подозрительно. Вы не можете скрыть тот факт, что соединение было потеряно с потоком, который активно передавал данные. Передача не может быть завершена, ее необходимо перезапустить. Некоторые ошибки слишком эффективны, чтобы их можно было обойти. Использование 15 потоков здесь не имеет особого смысла. Потоки покупают вам больше циклов процессора, это не ускоряет работу компьютера на другом конце провода.

Ответ №1:

Попробуйте написать что-то подобное в своем классе. Ваша процедура все еще может вызываться несколько раз, но ее фактическое тело будет выполняться только один раз за раз, если reconnected поле равно false .

 bool reconnected = false;
object lockObject = new object();

void ReconnectToSocket()
{
  lock(lockObject)
  {
    if(!reconnected) { /*do stuff*/; reconnected = true; }
  }
}
  

Комментарии:

1. Если использовать блокировку, и в сценарии, в котором 5 потоков одновременно вызывают процедуру ReconnectToSocket(), и 1-й получает блокировку, а затем ее ожидает оставшийся 4. Как только первый завершится, второй получит и снова выполнит ту же задачу. Я хочу избежать этого.

2. Вы правы, все потоки в конечном итоге получат блокировку, но они освободят ее без выполнения каких-либо задач из-за if(!reconnected) условия.

3. позвольте мне реализовать этот подход и протестировать.

Ответ №2:

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

Комментарии:

1. Мне нужно сохранить соединение на всем протяжении. Каждые 5-10 секунд сообщения и инструкции передаются с использованием соединения. Поэтому я не хочу открывать и закрывать соединение и не сохранять разные объекты для каждого потока.