Как предотвратить умирание потоков или просто выход в C # .NET? - PullRequest
0 голосов
/ 18 марта 2009

Я запускаю не более 5 потоков в программе на C # .NET. Но иногда некоторые из этих потоков просто прекращают работу или становятся необъяснимым образом мертвыми даже до завершения выполнения назначенной ему функции.

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

И иногда все потоки отлично выполняют назначенные функции. Они не делят между собой никаких ресурсов.

            Thread[] td = new Thread[5];
            for (count = 4; count >= 0; --count)
            {
                ds[count] = dba.getData(ru[count]);
                td[count] = new Thread(delegate() {  runRule[count].performTask(ru[count], ds[count], count); });
                td[count].Name = "Thread " + count.ToString();
                td[count].Start();
                Thread.Sleep(50);
            }

Если я удаляю последнюю строку «Thread.Sleep (50)», запускается только первый просмотр потоков, а остальные просто умирают.

Может кто-нибудь объяснить, почему темы становятся мертвыми?

Ответы [ 2 ]

4 голосов
/ 18 марта 2009

Я подозреваю, что они не становятся мертвыми - я подозреваю, что проблема в том, что вы на самом деле не соблюдаете те правила, о которых думаете. Когда вы используете локальные переменные метода в анонимном методе, сами переменные захватываются. В этом случае вы захватываете локальную переменную count и затем изменяете ее (по мере уменьшения счетчика цикла). К тому времени, когда поток, созданный при count = 4, начинает работать, count может быть 3 - поэтому он будет вызывать runRule[3].performTask(ru[3], ds[3], 3). На самом деле, count может изменить во время вычисления выражений , что может доставить массу удовольствия.

Способ обойти это состоит в том, чтобы иметь разные «локальные» переменные для каждой итерации цикла. Это легко сделать:

Thread[] td = new Thread[5];
for (count = 4; count >= 0; --count)
{
    int copy = count;
    ds[count] = dba.getData(ru[count]);
    td[count] = new Thread(delegate() {  
        runRule[copy].performTask(ru[copy], ds[copy], copy); 
    });
    td[count].Name = "Thread " + count.ToString();
    td[count].Start();
    Thread.Sleep(50);
}

Теперь единственными переменными, фиксируемыми в делегате, являются copy и runRule / ru / ds - я предполагаю, что последние три не меняются. Новый «экземпляр» переменной copy создается каждый раз, когда вы обходите цикл, поэтому изменения не будут мешать друг другу.

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

1 голос
/ 18 марта 2009

Если поток достигает конца своего пути выполнения, он автоматически заканчивается. В вашем примере, как только поток завершит работу, какой бы метод executeTask ни был, он завершится.

Если вы хотите, чтобы поток зависал вечно (только для целей отладки, так как вы не хотите, чтобы неиспользуемые потоки зависали в реальном приложении), вы можете добавить что-то вроде ниже в конец метода, который запущен потоком. .

ManualResetEvent stayAlive = new ManualResetEvent(false);
stayAlive.WaitOne();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...