현재 Microsoft Visual C# 2010 Express에서 코드를 작성하는 동안 CANBus adapter으로 작업하고 있습니다. CANBus 직렬 어댑터를 통해 TEKTRONIX 020-2924-XX DPO DEMO 2 보드에서 메시지를 읽는 별도의 스레드를 실행하는 GUI를 만들려고합니다.CANBus 어댑터의 숨겨진 코드에서 스레드 종료
나는 (setReceiveCallBackThread라고 불리는) 스레드를 종료하는 안전한 방법을 찾아 내려고 노력했다. 그러나이 특정 스레드는 스레드의 코드를 사용할 수 없다는 점에서 특별합니다. 이것은 CANBus API의 일부입니다.
스레드를 안전하게 중지하는 방법에 대해 웹 (특히 스택 오버플로)을 검색했습니다. 중단 방법을 사용하는 것이 최후의 수단이어야한다는 것을 발견했습니다.
그래서 스레드에서 중단을 사용할 수 없다고 결정하면 canplus_setReceiveCallBack 서브 루틴에서 예외 처리를 사용해야합니다. 그러나 문제는 canplus_setReceiveCallBack에 액세스 할 수 없다는 것입니다. 코드가 숨겨져 있습니다. 코드에 액세스 할 수 없기 때문에 이는 고유 한 상황임을 기억하십시오. 콜백 함수의 코드를 볼 수있는 다른 모든 상황과 달리이 서브 루틴의 코드는 볼 수 없습니다.
아래의 코드는 문제를 분석하는 데 필요한 모든 것이어야하며 스레드에서 Abort()를 사용하는 대신에 다른 방법이 필요합니다.
// CANSnifferForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class CANSnifferForm : Form
{
// per the api document. "This is a blocking call and must be called on a separate thread."
// the code previously after setCallback... was never being reached because the call is blocking.
// this calls the setCallbackThread function in another thread so processing can continue.
Thread setReceiveCallBackThread;
bool stop;
int can; // Return value of canplus_open
uint idFilter; // Filter values entered by user
ulong lenFilter;
bool stopThread; // Used for stopping thread
public CANSnifferForm()
{
InitializeComponent();
del = new EASYSYNC.CallbackDelegate(callback);
}
private void callback(ref EASYSYNC.CANMsg msg)
{
// Populate the dataGridView
if(InvokeRequired)
BeginInvoke(del, msg);
else
this.dataGridView1.Rows.Add(msg.id, msg.len, msg.data, msg.timestamp);
}
private EASYSYNC.CallbackDelegate del;
private void StartRestart_Click(object sender, EventArgs e)
{
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN closed");
this.ProcessStatusBox.Clear();
this.ProcessStatusBox.AppendText("Stopped");
EASYSYNC.CANMsg msg = new EASYSYNC.CANMsg();
msg.id = 1;
msg.timestamp = 2;
msg.flags = 3;
msg.len = 4;
msg.data = 5;
// Attempt to open CANBus adapter
can = EASYSYNC.canplus_Open(IntPtr.Zero, "1000", IntPtr.Zero, IntPtr.Zero, 0);
if (can < 0)
{
// CANBus Adapter not opened
this.ErrorBox.Clear();
this.ErrorBox.AppendText("Error opening CAN");
return;
}
// CANBus Adapter successfully opened
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN open");
// Initialize thread
setReceiveCallBackThread = new Thread(() => EASYSYNC.canplus_setReceiveCallBack(can, del));
// Attempt for CANBus adapter to listen
if (EASYSYNC.canplus_Listen(can) < 0)
{
// CANBus Adapter not listening
this.ErrorBox.Clear();
this.ErrorBox.AppendText("Error setting listen mode\n");
EASYSYNC.canplus_Close(can);
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN closed");
return;
}
// CANBus Adapter successfully listening
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN Listening\n");
// Place thread in background. Then start it
setReceiveCallBackThread.IsBackground = true;
setReceiveCallBackThread.Start();
while(!setReceiveCallBackThread.IsAlive);
this.ProcessStatusBox.Clear();
this.ProcessStatusBox.AppendText("Running\n");
}
private void FilterData_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Stop_Click(object sender, EventArgs e)
{
setReceiveCallBackThread.Abort(); // Stop thread
while (setReceiveCallBackThread.IsAlive == true)
{
}
this.ProcessStatusBox.Clear();
this.ProcessStatusBox.AppendText("Stopped");
// Attempt to flush CANBus Adapter
if (EASYSYNC.canplus_Flush(can) < 0)
{
// CANBus not flushing
this.ErrorBox.Clear();
this.ErrorBox.AppendText("Error flushing CAN");
EASYSYNC.canplus_Close(can); // Close CANBus Adapter
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN closed");
return;
}
// Attempt to reset CANBus Adapter
if (EASYSYNC.canplus_Reset(can) < 0)
{
// CANBus not resetting
this.ErrorBox.Clear();
this.ErrorBox.AppendText("Error resetting CAN");
EASYSYNC.canplus_Close(can); // Close CANBus Adapter
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN closed");
return;
}
this.CANSnifferStatusBox.Clear();
this.CANSnifferStatusBox.AppendText("CAN closed");
this.ErrorBox.Clear();
}
private void FilterID_KeyDown(object sender, EventArgs e)
{
}
private void FilterLength_KeyDown(object sender, EventArgs e)
{
}
private void FilterID_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
{
if (FilterIDBox.MaskFull)
{
}
else if (e.Position == FilterIDBox.Mask.Length)
{
}
else
{
}
}
private void FilterLength_MaskInputRejected(object sender, MaskInputRejectedEventArgs e)
{
if (FilterLengthBox.MaskFull)
{
}
else if (e.Position == FilterLengthBox.Mask.Length)
{
}
else
{
}
}
}
}
내 원래의 대답은 정확 편집을 확인하십시오
귀하의 Stop_Click 방법으로 스레드를 중지 할 수 있습니다. – Tergiver
그래, 이런 종류의 코드는 다루기가 매우 어려운 카테고리에 들어 맞습니다. .NET에서 호출 할 수있는 모든 종류의 산업용 버스 인터페이스는 실제로 원시 코드로 구현됩니다. COM은 상용구입니다. 이러한 코드를 중단하면 중단없이 관리되는 코드 만 일관된 방식으로 중단 될 수 있습니다. 기본 Winapi 호출 WaitForSingleObjectEx(), bAlertable 인수를 사용합니다. 모두가 비 Ex 버전을 사용하거나 FALSE를 전달합니다. 이것이 가능하다면 포기해야 할 것입니다. –
실제로 WaitFor에서 블로킹 중이며 중지 할 수없는 경우, 'Thread.IsBackgroundThread' 속성을 true로 설정하면 응용 프로그램이 종료 될 때 종료됩니다. – Tergiver