CancellationTokenSource로 취소 한 후 작업을 기다릴 때 문제가 있습니다. 취소 호출은 작업을 방해하지 않습니다. 작업이 중단되지 않으므로 주 스레드가 차단하는 작업에 대해 을 대기합니다.CancellationTokenSource misbehavior
내 프로그램에 대한 간단한 설명은 다음과 같습니다. 작업은 char 변수 ('A'에서 'Z'까지)를 증가시키고 GUI 스레드에 표시합니다. 이 작업을 수행하기 위해 컨트롤이 작성된 스레드에서 대리자 (this.invoke())를 실행합니다.
RefreshTextBox() 함수를 주석 처리하는 즉시 취소 호출이 작동하고 작업이 중단됩니다. this.invoke() 명령이 작업이 방해를 막는 것처럼 보입니다.
아래 코드는 일반 스레드와 동일한 기능을 구현했습니다. 그리고 나서 나는 일한다. 작업 구현과 스레드 구현의 차이점은 무엇입니까?
using System.Windows.Forms;
using System.Threading;
using System.Threading.Tasks;
public partial class frm_Main : Form
{
private delegate void dgt_StringHandler(string str_Value);
CancellationTokenSource _obj_Cts = null;
Thread _obj_Thread = null;
Task _obj_Task = null;
public frm_Main()
{
InitializeComponent();
}
private void CreateChar(ref char chr_Value)
{
int int_Value;
int_Value = (int)chr_Value;
int_Value++;
if (int_Value > 90 || int_Value < 65)
int_Value = 65;
chr_Value = (char)int_Value;
}
private void TestThread()
{
char chr_Value = '@';
bool bol_Stop = false;
while (!bol_Stop)
{
try
{
Thread.Sleep(300);
CreateChar(ref chr_Value);
RefreshTextBox(chr_Value.ToString());
}
catch (ThreadInterruptedException)
{
bol_Stop = true;
}
}
}
private void TestTask(object obj_TokenTmp)
{
char chr_Value = '@';
CancellationToken obj_Token = (CancellationToken)obj_TokenTmp;
while (!obj_Token.IsCancellationRequested)
{
Thread.Sleep(300);
CreateChar(ref chr_Value);
RefreshTextBox(chr_Value.ToString());
}
}
private void RefreshTextBox(string str_Value)
{
if (txt_Value.InvokeRequired)
{
dgt_StringHandler obj_StringHandler = new dgt_StringHandler(RefreshTextBox);
this.Invoke(obj_StringHandler, new object[] { str_Value });
}
else
{
txt_Value.Text = str_Value;
}
}
private void btn_StartStop_Click(object sender, EventArgs e)
{
if (_obj_Task == null && _obj_Thread == null)
{
if (opt_Task.Checked)
{
_obj_Cts = new CancellationTokenSource();
_obj_Task = new Task(new Action<object>(TestTask), _obj_Cts.Token, _obj_Cts.Token);
_obj_Task.Start();
}
else
{
_obj_Thread = new Thread(new ThreadStart(TestThread));
_obj_Thread.Start();
}
btn_StartStop.Text = "Stop";
}
else
{
if (_obj_Thread != null)
{
_obj_Thread.Interrupt();
_obj_Thread.Join();
_obj_Thread = null;
}
if (_obj_Task != null)
{
_obj_Cts.Cancel();
_obj_Task.Wait();
_obj_Task = null;
_obj_Cts = null;
}
btn_StartStop.Text = "Start";
}
}
}
답장을 보내 주셔서 감사합니다. 그러나 이것은 문제의 해결책이 아닙니다. CancellationTokenSource로 취소 할 수없는 이유를 알고 싶습니다. Wait 문을 주석 처리 할 때 작업이 백그라운드에서 계속 실행되고있는 경우 (또는 내 경우에는 블로킹) 백그라운드에서 실행되지 않고 끝나지 않습니다. –
Interrupt() 및 Join() 호출시 같은 루틴이 일반 스레드에서 작동하는 이유는 분명하지 않습니다. 그리고 그것을 작업으로 구현하고 Cancel()을 호출 한 다음 Wait()을 호출하면 작동하지 않습니다. 차이점은 어디입니까? refreshbox() 메서드를 주석 처리 할 때 Cancel() 및 Wait()도 작업 구현과 함께 작동합니다! –
"작업이 아직 실행 중입니다."- 그러면 문제가 있습니다. 취소는 협동 작업입니다. 당신의 과제는 끝나야합니다. Thread.Interrupt (또는 .Abort)는 강력하지만 안전하지 않습니다. –