Всем привет, уже третий день не могу разобраться с доп. потоком, вернее с синхронизацией. Нужна помощь, т.к. я только начал программировать на C# в VS2012.
Задача: На форме две кнопки - "Start thread" и "Stop thread" и поле - richTextBox.
При нажатии на кнопку "Start thread" останавливается поток, если он был создан, иначе создается доп. поток в котором выводится инфа в richTextBox.
При нажатии на кнопку "Stop thread" поток должен корректно остановится, т.е. не убить поток, а в экстренном случаи должен завершить свою работу.
При закрытии приложении, если поток в работе необходимо опять же корректно остановить его.
Казалось все просто, но я столкнулся с проблемой: программа виснет.
[more="Вот мой код:"]using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication10
{
delegate void SetTextCallback(string text);
public partial class Form1 : Form
{
Thread th;
public Form1()
{
InitializeComponent();
}
private void SetText(string text)
{
richTextBox1.AppendText(text + "\n");
}
public void SetTextSafe(string value)
{
if (richTextBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
Invoke(d, new object[] { value + " (Invoke)" });
}
else
{
// It's on the same thread, no need for Invoke
SetText(value + " (No Invoke)");
}
}
public void StopThread()
{
if (th != null)
{
th.Interrupt();
th.Join(); // Здесь зависон !!!
// если зделать, так:
//while (th.Join(10) == false) { Application.DoEvents(); }
// то казалось бы все решено, но из-за DoEvents() возникают другие проблеммы, такие как повторный вход в тот же метод StopThread()
SetTextSafe("OK...");
SetText("");
th = null;
}
}
public void StartThread()
{
StopThread();
th = new Thread(new ThreadStart(this.ThreadProcSafe));
SetTextSafe("GO...");
th.Start();
}
private void ThreadProcSafe()
{
SetTextSafe("Start...");
try
{
int i = 0;
while (i < 1000)
{
SetTextSafe(i.ToString());
i++;
Thread.Sleep(100);
}
}
catch (ThreadInterruptedException)
{
SetTextSafe("terminate");
}
SetTextSafe("stop");
}
private void Safebutton_Click(object sender, EventArgs e)
{
StartThread();
}
private void button2_Click(object sender, EventArgs e)
{
StopThread();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
StopThread();
}
}
}
[/more]
Результат должен быть такой: [more]GO... (No Invoke)
Start... (Invoke)
0 (Invoke)
1 (Invoke)
2 (Invoke)
3 (Invoke)
4 (Invoke)
terminate (Invoke)
stop (Invoke)
OK... (No Invoke)
GO... (No Invoke)
Start... (Invoke)
0 (Invoke)
1 (Invoke)
2 (Invoke)
3 (Invoke)
4 (Invoke)
terminate (Invoke)
stop (Invoke)
OK... (No Invoke)[/more]
Как я понял зависон из-за th.
Join();, т.к. он блокирует вызывающий поток до завершения доп. потока. Но при этом доп. поток хочет синхронно вывести инфу в richTextBox - "terminate" и "stop", а основной поток приостановлен (блокирован).
Пытался c
AutoResetEvent autoEvent вместо th.Join(); использовал autoEvent.WaitOne(), результат тот же - зависон на autoEvent.WaitOne()