C# 在CANBus适配器的隐藏代码中终止线程
我目前正在使用Microsoft Visual C 2010 Express为其编写代码。我正在尝试制作一个GUI,它运行一个单独的线程,用于通过CAN总线串行适配器读取来自TEKTRONIX 020-2924-XX DPO DEMO 2板的消息 我试图找出终止名为setReceiveCallBackThread的线程的安全方法。然而,这个特殊的线程是特殊的,因为线程的代码不可用。它是CAN总线API的一部分 我在网上搜索过,特别是关于如何安全停止线程的堆栈溢出。我发现使用abort方法应该是最后的选择 因此,如果我决定不能在线程上使用abort,我必须在canplus_setReceiveCallBack子例程中使用异常处理。但是,问题是我无法访问canplus_setReceiveCallBack;代码是隐藏的。请记住,这是一种独特的情况,因为我无法访问代码。与可以看到回调函数代码的所有其他情况不同,无法看到此子例程中的代码 下面的代码应该是您分析问题所需的全部内容,并有望找到一种替代方法来替代在线程上使用AbortC# 在CANBus适配器的隐藏代码中终止线程,c#,multithreading,terminate,abort,C#,Multithreading,Terminate,Abort,我目前正在使用Microsoft Visual C 2010 Express为其编写代码。我正在尝试制作一个GUI,它运行一个单独的线程,用于通过CAN总线串行适配器读取来自TEKTRONIX 020-2924-XX DPO DEMO 2板的消息 我试图找出终止名为setReceiveCallBackThread的线程的安全方法。然而,这个特殊的线程是特殊的,因为线程的代码不可用。它是CAN总线API的一部分 我在网上搜索过,特别是关于如何安全停止线程的堆栈溢出。我发现使用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
{
}
}
}
}
我原来的回答是不正确的。根据API指南 定义一个函数,该函数将在所有传入 信息。这是一个阻塞调用,必须在单独的 线要取消注册此回调函数,请 canplus_setReceiveCallback可以在cbfn等于NULL的情况下调用 文档没有说明被阻止的调用何时退出,所以我猜当您使用NULL调用canplus_setReceiveCallback时,它会退出 我没有一种简单的方法来测试它,但是您可以通过在原始调用返回时输出文本来验证这一点
setReceiveCallBackThread = new Thread(() => { EASYSYNC.canplus_setReceiveCallBack(can, del); Trace.WriteLine("EASYSYNC thread terminated"); });
您的Stop_Click方法可以通过以下方式停止线程:
EASYSYNC.canplus_setReceiveCallBack(can, null);
我原来的答案不正确,请检查编辑。是的,这种代码适合一个很难处理的类别。任何可从.NET调用的工业总线接口实际上都是在本机代码中实现的。COM是样板。中止这样的代码是不可能的,只有托管代码才能以一致的方式中止。底层winapi调用是WaitForSingleObjectEx,它接受一个bAlertable参数。每个人要么使用非Ex版本,要么传递FALSE。您必须放弃假设这是可能的。如果它确实在WaitFor上阻塞并且无法停止,请将Thread.IsBackgroundThread属性设置为true,以便在应用程序退出时终止它。除非我实际断开计算机的CAN总线和Demoboard连接,否则线程似乎不会停止。我甚至使用了逻辑来确保代码只有在线程完成时才会继续。我想我真的没有什么可以做的了。但我还是像往常一样感谢你。你的回答很有帮助!!