У меня возникли проблемы с пониманием того, почему мое консольное приложение не ждет, пока поток, который он порождает , полностью завершает работу. Я думаю, что это связано с тем, что рассматриваемая нить порождает собственные потоки детей и/или включение System.TimerКонсольное приложение не подчиняется Thread.Join
Основной поток программы выглядит следующим образом. Main создает новый поток против метода Simulator.Start и затем присоединяется, пока этот поток не завершится. Simulator.Start создает новый Timer
(чтобы ограничить время его выполнения), а затем создает/запускает кучу дочерних потоков. Когда событие Elapsed
возбуждается Timer
, это означает, что Симулятор должен прекратить все свои дочерние потоки и сгенерировать отчет. Проблема заключается в том, что консольное приложение завершается, как только все дочерние потоки завершаются, а код для создания отчета никогда не запускается (см. Метод Simulator.Stop ниже).
Надеюсь, некоторые псевдо-код поможет:
public class Program
{
private static Simulator _simulator;
private static void Main(string[] args)
{
var options = new SimulationOptions();
//check for valid options
if (!Parser.Default.ParseArguments(args, options)) return;
_simulator = new Simulator(options);
var thread = new Thread(_simulator.Start) {IsBackground = false};
thread.Start();
thread.Join();
}
}
public class Simulator
{
private readonly SimulationOptions _options;
private readonly List<Thread> _threads = new List<Thread>();
private readonly List<Worker> _workers = new List<Worker>();
private static Timer _timer;
public Simulator(SimulationOptions options)
{
_options = options;
StartTimer(_options.LengthOfTest);
}
private void StartTimer(int lengthOfTest)
{
_timer = new Timer {Interval = lengthOfTest*1000};
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
Stop();
}
public void Stop()
{
// Request that the worker thread stop itself:
foreach (Worker worker in _workers)
{
worker.RequestStop();
}
GenerateReport(); //<-- this code never gets executed
}
private XDocument GenerateReport()
{
//build an awesome report
}
public void Start()
{
_threads.Clear();
_workers.Clear();
for (int i = 0; i < _options.NumberOfClients; i++)
{
_workers.Add(new Worker());
_threads.Add(new Thread(_workers.Last().PumpMessages));
_threads.Last().Start();
}
}
}
public class Worker
{
private bool _shouldStop = false;
public void PumpMessages()
{
while (!_shouldStop)
{
//does cool stuff until told to stop
}
}
public void RequestStop()
{
_shouldStop = true;
}
}
Конечно, он проходит через метод Start(), занимает не более нескольких микросекунд. Вначале просто не было смысла называть Start() для рабочего потока. Вам необходимо присоединиться() все эти потоки, которые вы запускаете. –
Проблема не в методе «Пуск». Консольное приложение зависает достаточно долго для события Timer_Elapsed, которое запускает метод Stop. Однако выполнение заканчивается в середине этого метода. –