我正在使用CANBus adapter,同時目前正在使用Microsoft Visual C#2010 Express編寫它的代碼。我試圖製作一個GUI,它運行一個單獨的線程,通過CANBus串行適配器從TEKTRONIX 020-2924-XX DPO DEMO 2板讀取消息。在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
{
}
}
}
}
我原來的答覆是不正確的,檢查編輯。 – Tergiver 2012-07-23 22:03:04
是的,這種代碼適合很難處理的類別。任何一種可從.NET調用的工業總線接口實際上都是用本地代碼實現的。 COM是樣板。中止這樣的代碼是一個不可行的過程,只有託管代碼可以以一致的方式中止。底層的winapi調用是WaitForSingleObjectEx(),它需要一個bAlertable參數。每個人都使用非Ex版本或傳遞FALSE。假設這是可能的,你將不得不放棄。 – 2012-07-23 22:21:40
如果確實阻塞了WaitFor並且無法停止,請將Thread.IsBackgroundThread屬性設置爲true,以便在應用程序退出時終止它。 – Tergiver 2012-07-23 23:24:28