1

現在、Microsoft Visual C# 2010 Express でコードを書いているときに、CANBus アダプターを使用しています。CANBus シリアル アダプタを介して TEKTRONIX 020-2924-XX DPO DEMO 2 ボードからメッセージを読み取るための別のスレッドを実行する GUI を作成しようとしています。

スレッドを安全に終了する方法を見つけようとしました (setReceiveCallBackThread と呼ばれます)。ただし、この特定のスレッドは、スレッドのコードが使用できないという点で特別です。CANBus API の一部です。

スレッドを安全に停止する方法について、Web (特にスタック オーバーフロー) を検索しました。私は、abort メソッドを使用することが常に最後の手段であることを発見しました。

したがって、スレッドでアボートを使用できないと判断した場合は、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
            {

            }

        }
    }
}
4

1 に答える 1

0

私の最初の答えは間違っていました。APIガイドによると

すべての着信メッセージでコールバックを受け取る関数を定義します。これはブロッキング呼び出しであり、別のスレッドで呼び出す必要があります。このコールバック関数を登録解除するには、cbfn を NULL にして canplus_setReceiveCallback を呼び出すことができます。

ドキュメントには、ブロックされた呼び出しがいつ終了するかは記載されていないため、NULL で canplus_setReceiveCallback を呼び出したときに終了すると推測されます。

簡単にテストする方法はありませんが、元の呼び出しが戻ったときにテキストを出力することでこれを確認できます。

setReceiveCallBackThread = new Thread(() => { EASYSYNC.canplus_setReceiveCallBack(can, del); Trace.WriteLine("EASYSYNC thread terminated"); });

Stop_Click メソッドは、次の方法でスレッドを停止できます。

EASYSYNC.canplus_setReceiveCallBack(can, null);
于 2012-07-23T21:34:45.570 に答える