Переменная таинственно меняющаяся величина - PullRequest
1 голос
/ 13 января 2011

РЕДАКТИРОВАТЬ: Хорошо, у меня была проблема с одной из функций конкатенации строк, не имеет никакого отношения к потокам, но зная, что это не может быть проблемой с потоками, привело меня к ответу спасибо за ответ.

Я делаю простую программу чата tcp / ip для отработки потоков и tcp / ip. Я использовал асинхронные методы, но у меня была проблема с параллелизмом, поэтому я перешел к потокам и методам блокировки (не асинхронным). У меня есть две частные переменные, определенные в классе, а не статические:

string amessage = string.Empty;
int MessageLength;

и нить

private Thread BeginRead;

Хорошо, поэтому я вызываю функцию Listen ONCE при запуске клиента:

public virtual void Listen(int byteLength)
        {
            var state = new StateObject {Buffer = new byte[byteLength]};
            BeginRead = new Thread(ReadThread);
            BeginRead.Start(state);                
        }

и, наконец, функция для получения команд и их обработки, я собираюсь сократить их, потому что они действительно длинные:

  private void ReadThread(object objectState)
    {
       var state = (StateObject)objectState;
       int byteLength = state.Buffer.Length;
       while (true)
          {

              var buffer = new byte[byteLength];
              int len = MySocket.Receive(buffer);
              if (len <= 0) return;               
              string content = Encoding.ASCII.GetString(buffer, 0, len);
              amessage += cleanMessage.Substring(0, MessageLength);
              if (OnRead != null)
                {
                   var e = new CommandEventArgs(amessage);
                   OnRead(this, e);
                 }

           }

    }

Теперь, насколько я понимаю, только один поток за раз будет вводить BeginRead, я звоню Receive, он блокируется до тех пор, пока я не получу данные, а затем обработаю их. Проблема: переменная amessage изменит свое значение между операторами, которые вообще не касаются или не изменяют переменную, например, в нижней части функции по адресу: if (OnRead != null) «amessage» будет равно «asdf» и в if (OnRead != null) "amessage" будет равен qwert. Насколько я понимаю, это указывает на то, что другой поток изменяет значение / работает асинхронно. Я только порождаю один поток для получения, а функция Receive блокирует, как может быть два потока в этой функции, и если есть только один поток, как значение amessage изменяется между операторами, которые не влияют на его значение. В качестве примечания, извините за спам на сайте с этими вопросами, но я только знакомлюсь с этой многопоточной историей, и это заставляет меня хотеть потягивать цианид.

Заранее спасибо.

EDIT:

Вот мой код, который вызывает метод Listen в клиенте:

public void ConnectClient(string ip,int port)
        {

            client.Connect(ip,port);
            client.Listen(5);
        }

и на сервере:

private void Accept(IAsyncResult result)
        {

                var client = new AbstractClient(MySocket.EndAccept(result));
                var e = new CommandEventArgs(client, null);
                    Clients.Add(client);
                    client.Listen(5);
                    if (OnClientAdded != null)
                    {
                        var target = (Control) OnClientAdded.Target;
                        if (target != null && target.InvokeRequired)
                            target.Invoke(OnClientAdded, this, e);
                        else
                            OnClientAdded(this, e);


                    }


                    client.OnRead += OnRead;
                    MySocket.BeginAccept(new AsyncCallback(Accept), null);

        }

Весь этот код находится в классе с именем AbstractClient. Клиент наследует абстрактный клиент, и когда сервер принимает сокет, который он создает, он создает собственный локальный AbstractClient, в этом случае оба модуля обращаются к функциям, описанным выше, однако это разные экземпляры, и я не мог представить себе, что потоки из разных экземпляров объединяются, тем более что ни одна переменная не является статичный.

Ответы [ 2 ]

3 голосов
/ 13 января 2011

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

Общий подход заключается в добавлении регистрации в ваш код. Обсыпайте ваш код операторами Debug.WriteLine (), которые показывают текущее значение переменной, а также ManagedId потока. Вы получаете потенциально много продукции, но где-то вы увидите, что она идет не так. Или вы получите достаточно информации о том, как взаимодействуют потоки, чтобы угадать источник проблемы.

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

1 голос
/ 13 января 2011

Я предполагаю, что OnRead запускает событие, отправленное в поток пула потоков. Если какой-либо зарегистрированный обработчик событий записывает в amessage, его значение может измениться в любое время, когда вы находитесь в цикле чтения.

По-прежнему не очень ясно, откуда вы получаете значение, присвоенное amessage в цикле. cleanmessage читать content?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...