Изменить свойство класса из другого потока в C # - PullRequest
3 голосов
/ 14 апреля 2011

У меня есть класс C #, который выполняет бесконечный цикл, пока условная переменная не будет установлена ​​в значение true. Есть другой класс, который ожидает сетевого сообщения, и когда сообщение получено, есть вызов к другому классу, чтобы изменить условную переменную на true, чтобы он мог выйти из цикла while. Ожидание сообщения осуществляется в отдельном потоке:

Класс модификатора:

public class Modifier{
Otherclass log;
private static NetworkStream theStream;
private StreamReader theInput;

public Modifier(Otherclass other, NetworkStream str)
            {
                this.log = other;
                theStream = str;
                theInput = new StreamReader(theStream);
                Thread listenThread = new Thread(new ThreadStart(listen));
                listenThread.Start();
            }

            public void listen()
            {
                while (true)
                {
                    log.postMessage(theInput.ReadLine());
                }
            }
}

А другой класс:

public class Otherclass{
    bool docontinue = true;
    public void postMessage(string input)
    {
         docontinue = true;
    }

    public void wait()
    {
          while(!docontinue)
          {
          }
    }
}

Проблема в том, что программа застревает во время (! Docontinue), хотя сообщение отправлено. Я подозреваю, что проблема в том, что переменная docontinue не изменяется, но я не знаю, если проблема в другом месте.

Ответы [ 5 ]

7 голосов
/ 14 апреля 2011

Здесь есть различные проблемы -

Первый и прямой ответ на ваш вопрос заключается в том, что вам необходимо объявить свое логическое поле, используя volatile :

private volatile bool doContinue = true;

Это, как говорится, наличие цикла, который делает цикл while без тела, очень плохо - он будет использовать 100% CPU в этом потоке и просто "вращаться" бесконечно.

Гораздо лучший подход кв таких ситуациях нужно заменить цикл while на WaitHandle, например ManualResetEvent .Это позволяет вам ждать события сброса и блокировать, пока вы не будете готовы продолжить.Вы вызываете Set () для него в другом потоке, чтобы продолжить выполнение.

Например, попробуйте это:

public class Otherclass{
    ManualResetEvent mre = new ManualResetEvent(false);

    public void PostMessage(string input)
    {
         // Other stuff here...
         mre.Set(); // Allow the "wait" to continue
    }    

    public void Wait()
    {
          mre.WaitOne(); // Blocks until the set above
    }
}
0 голосов
/ 14 апреля 2011

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

public class Otherclass{
    bool docontinue = true;
    public void postMessage(string input)
    {
         docontinue = true;
    }

    public void wait()
    {
          while(!docontinue)
          {
          }
    }
}

docontinue не меняет значения. Он начинается как true, и вы устанавливаете его в true, когда сообщение публикуется. Кроме того, в предложении while нет условия, поэтому цикл никогда не должен выполняться, поскольку !docontinue всегда ложно.

0 голосов
/ 14 апреля 2011

У вас есть два (потенциально) бесконечных цикла здесь. И на самом деле ничто не вызывает Wait ()

Есть ли веская причина, по которой вам нужно тратить циклы в фиктивном цикле внутри метода ожидания? Какую цель он служит?

Мне кажется, что postMessage должен запустить новый поток, который будет выполнять любую работу, которую необходимо выполнить после того, как Wait () должен прерваться.

0 голосов
/ 14 апреля 2011

Попробуйте добавить Thread.Sleep (100) в свой цикл. Также рассмотрите возможность использования класса ManualResetEvent .

ОБНОВЛЕНИЕ: Я только что проверил, wait () завершает работу даже без Thread.Sleep, volatile и других вещей. Но мое тестовое консольное приложение зависает, потому что the listen () никогда не заканчивается ...

0 голосов
/ 14 апреля 2011

Вы можете использовать Летучий

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