2016-08-08 4 views
0

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

threads = 0; 
Algorithm(array) { 
    //some code... 

    newArray1 = array.Take(array.Length/2).ToArray(); 
    newArray2 = array.Skip(array.Length/2).ToArray(); 

    ThreadStart start1 = delegate 
     { 
      Algorithm(newArray1); 
     }; 

    Thread thread1 = new Thread(start1); 

    ThreadStart start2 = delegate 
     { 
      Algorithm(newArray2); 
     }; 

    Thread thread2 = new Thread(start2); 
    thread1.Start(); 
    threads++; 
    thread2.Start(); 
    threads++; 
} 

Это не имеет значения, насколько глубоко эта рекурсия идет, переменная нити всегда равна 2. Зачем?

+1

Поскольку оба потока имеют одну и ту же переменную 'threads' – user3185569

+0

@ user3185569, поэтому область не имеет значения для потоков? – WhilseySoon

+1

Вы не устанавливаете общую переменную как [раздел взаимного исключения] (https://en.wikipedia.org/wiki/Mutual_exclusion). Это может привести к некоторому решению проблемы несоответствия, так как хорошая практика должна быть в разделе взаимного исключения. И когда вы ждете/присоединяетесь к ним, чтобы синхронизировать его? – Raskayu

ответ

2

Я предполагаю, что вы не ждали завершения нитей. Вам нужно добавить внутри метода Algorithm вызов метода Thread.Join() (documentation), который «блокирует вызывающий поток, пока поток, представленный этим экземпляром, не завершится» (вы сделаете это как для, так и для thread2). Кроме того, вам нужно будет использовать класс Interlocked, который «предоставляет атомарные операции для переменных, которые разделяются несколькими потоками», чтобы увеличить количество потоков (см. Increment method).

Сказав это, вы должны иметь в виду, что создание новых потоков для отдельных задач крайне неэффективно (есть накладные расходы на производительность при создании потоков/переключение контекста). Вместо этого вы должны использовать пул потоков, предоставляемый CLR. Если вы хотите получить дополнительную информацию о том, как использовать параллелизм задач для эффективного использования пула потоков, см. this link

+0

Спасибо. И еще одно: я использовал 'thread1.Abort(); thread2.Abort(); 'в конце функции. Да, я знаю, что это плохо, но у меня есть вопрос: в отладке я вижу только два ** исключения ThreadAbortException **, но на самом деле существует 8 уровней рекурсии! Так что на самом деле существуют только две темы. Зачем? – WhilseySoon

+0

Я бы не стал полагаться на это исключение, чтобы узнать, сколько потоков было запущено. Попробуйте добавить следующий код в начало вашего метода 'Algorithm'' Console.WriteLine («Current thread id: {0}», Thread.CurrentThread.ManagedThreadId); вместо – oldbam

+0

Он запускается только один раз: 'Текущий идентификатор потока: 9 ' – WhilseySoon

1

Да, переменная threads является общей. Посмотрите на эту ссылку для использования потоков с рекурсивными функциями - How to use threads with a recursive template function

+0

Но если переменная является общей, не должна ли рекурсивность увеличивать ее * выше * 2? Вероятно, здесь есть проблемы с блокировкой и гонками, но если OP прав, переменная * всегда * содержит значение 2, то это не так странно? –

Смежные вопросы