国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

英創信息技術嵌入式系統通訊線程的C#編程方法

英創信息技術 ? 來源:英創信息技術 ? 作者:英創信息技術 ? 2020-01-15 11:25 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在使用英創ARM9系列嵌入式主板的COM口,CAN口,網口時,一般會使用到timer或線程來實現數據的接收。使用timer控件較為方便,通過InterVal值來設定調用間隔,但是靈活性不如線程。并且timer的Tick函數是并在主線程中,如果Tick函數中運算數據過于復雜,會導致主線程運行變慢,可能導致窗口卡死。使用C#中的線程類,可以非常方便的解決這個問題,線程卡死,不會影響到主線程的運算,就不會導致窗口卡死的狀況發生。

本文將介紹如何使用C#來創建和關閉線程,并在此基礎上,利用WinCE系統的消息機制實現通訊數據的實時收發,代替常規的定時查詢方法,從而降低了CPU負載,使嵌入式設備的整體性能得以提高。

1、線程的應用實例

以下是一個簡單的多線程代碼:

using System;
using System.Threading;
namespace thread
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(excute);
t.Start();
while (true) Console.Write('1'); // 主線程循環輸出1
}
static void excute()
{
while (true) Console.Write('2'); // 線程t循環輸出2
}
}
}

輸出例子(并不唯一):12121212121212121212121212121212121212121212121212...

2、線程的使用方法

首先需要添加thread類的引用

using System.Threading;

初始一個線程類,并設定它的執行函數,該函數可以是靜態函數,也可以是別的類的成員函數

Thread t = new Thread(excute);

執行start,線程即啟動并運行它的執行函數,函數運行完畢后,線程自動退出

t.Start();

3、線程的數據同步

觀察以下代碼:

using System;
using System.Threading;
namespace thread
{
class Program
{
static int i;
static void Main(string[] args)
{
Thread t = new Thread(excute);
t.Start();
excute();
}
static void excute()
{
for (i = 0; i < 5; i++)
{
Console.Write('{0}', i);
}
}
}
}

這個程序的輸出無法確定,可能是:001234。

這是因為在一個線程在使用一個變量時,另外一個線程也可能同時在使用。如果希望一個線程在使用某個變量時,禁止其他線程的使用,就需要用到線程鎖lock。

修改代碼為:

using System;
using System.Threading;
namespace thread
{
class Program
{
static readonly object locker = new object();
static int i;
static void Main(string[] args)
{
Thread t = new Thread(excute);
t.Start();
excute();
}
static void excute()
{
lock (locker)
{
for (i = 0; i < 5; i++)
{
Console.Write('{0}', i);
}
}
}
}
}

程序輸出:0123401234。

注意lock的使用,見MSDN的說明:

1、不要鎖定this,即禁止lock(this)
2、不要鎖定類型,如lock (typeof (MyType))
3、不要鎖定字符串,如lock('myLock')
4、最佳做法是定義private或 private static對象來鎖定

鎖定本身是很快,一個鎖在堵塞的情況,任務切換帶來的開銷很低,使用鎖可以有效避免一些數據錯誤,提高程序穩定性。

4、線程的結束

使用abort可以提前釋放被阻塞的線程,使用join可以等待線程的結束:

using System;
using System.Threading;
namespace thread
{
class Program
{
static int i;
static void Main(string[] args)
{
Thread t = new Thread(excute);
t.Start();
// t.Abort();
t.Join();
for (i = 6; i < 10; i++)
{
Console.Write('{0}', i);
}
}
static void excute()
{
for (i = 0; i < 5; i++)
{
Console.Write('{0}', i);
}
}
}
}

程序輸出:0123456789。

如果取消Abort的注釋,程序的輸出可能是:6789。

在主線程中關閉副線程一般步驟為,終止副線程,再等待確認該線程退出,在主程序退出的時間同樣需要執行檢測副線程的關閉:

t.Abort();
t.Join();

5、帶參數的線程

有時候希望在添加的線程中傳入指定的參數。

最簡單的辦法是把類封裝在類中,讓線程的執行函數為類的成員函數,然后通過設置類的成員變量,執行函數訪問成員變量這樣的辦法來實現指定執行函數參數的功能,例程如下:

using System;
using System.Threading;
namespace thread
{
class ThreadClass
{
public int x;
public void excute()
{
while (true) { Console.WriteLine('{0}', x); }
}
}
class Program
{
static void Main(string[] args)
{
ThreadClass TClass1 = new ThreadClass();
TClass1.x = 1;
ThreadClass TClass2 = new ThreadClass();
TClass2.x = 2;
Thread t1 = new Thread(TClass1.excute);
Thread t2 = new Thread(TClass2.excute);
t1.Start();
t2.Start();
}
}
}

還有一個另外的辦法,使用ParameterizedThreadStart。

C#提供2種委托,ThreadStart和ParameterizedThreadStart,ParameterizedThreadStart允許傳入一個參數Object,可以將所需參數打包后調用。

注意:wince使用的是.net精簡庫,不包含ParameterizedThreadStart,如果在wince下編程,請使用第一種方法。

6、線程的掛起和喚醒

當線程創建后,就將占用一定的CPU時間,可以使用Sleep函數讓線程放棄一定時間片,進入休眠狀態,在休眠狀態下,線程將不再占用CPU時間,如:

Thread.Sleep(0); // 釋放CPU時間片
Thread.Sleep(1000); // 休眠1000毫秒
Thread.Sleep(Timeout.Infinite); // 休眠直到被喚醒

使用線程的Interrupt方法可以強行喚醒休眠中的線程,注意,wince的.net精簡庫里,Thread類沒有Interrupt方法,所以在嵌入式設備中開發時不要無限休眠線程,即Sleep(-1)。

7、線程的消息事件響應

有的時候需要在線程中輪詢執行一個函數,如通信接口的接收函數。使用輪循的方式將非常浪費CPU時間。

private void BeginReceive() // 客戶機狀態下接收數據線程
{
while (!threadStop)
{
// 線程接收函數
}
}

在接收線程中加入適當休眠可以提高CPU效率,這里Sleep的x越大,CPU效率越高,但是可能造成數據處理的延時。

private void BeginReceive() // 客戶機狀態下接收數據線程
{
while (!threadStop)
{
// 線程接收函數
Thread.Sleep(x); // 輪詢休眠
}
}

為了避免通訊數據接收的延時,線程還可采用等待數據接收事件的方式,線程在平時掛起,直到有數據接收的事件產生。
C#提供一套事件類,可以讓線程進入等待狀態,直到該事件到來,線程在等待時不會消耗CPU資源。

using System;
using System.Threading;
namespace thread
{
class Program
{
static AutoResetEvent evt;
static void Main(string[] args)
{
evt = new AutoResetEvent(false);
Thread t = new Thread(excute);
t.Start();
Thread.Sleep(10000);
evt.Set();
}
static void excute()
{
for ( ; ; )
{
evt.WaitOne();
Console.Write('event');
}
}
}
}

設定一個事件

static AutoResetEvent evt;

在線程等待該事件的時候掛起

evt.WaitOne();

直到該事件Set產生,線程才繼續執行下面的代碼:

evt.Set();

還可以設置等待的時間長短,當有事件產生,WaitOne函數立刻返回true,如果等待時間超過設置時間,WaitOne也會返回,返回值false。

using System;
using System.Threading;
namespace thread
{
class Program
{
static AutoResetEvent evt;
static void Main(string[] args)
{
evt = new AutoResetEvent(false);
Thread t = new Thread(excute);
t.Start();
evt.Set();
Thread.Sleep(1000);
evt.Set();
Thread.Sleep(10000);
evt.Set();
}
static void excute()
{
bool b;
for (; ; )
{
b = evt.WaitOne(1000, false);
Console.Write('{0}', b.ToString);
}
}
}
}

注意:WaitOne第二個參數一般設置為false。

但是使用C#的事件類可能有一定局限性,它需要在同一進程里,有一些情況無法滿足需要。這時候可以使用系統的API函數來解決這個問題,參看以下代碼。

using System;
using System.Threading;
using System.Runtime.InteropServices;
namespace thread
{
class Program
{
[DllImport('coredll.dll', EntryPoint = 'WaitForSingleObject')]
private static extern int WaitForSingleObject(int hHandle, int dwMilliseconds);
[DllImport('coredll.dll', EntryPoint = 'CreateEvent')]
private static extern int CreateEvent(int lpEventAttributes, int bManualReset, int bInitialState, int lpName);
[DllImport('coredll.dll', EntryPoint = 'EventModify')]
private static extern bool EventModify(int h, int i);
[DllImport('coredll.dll', EntryPoint = 'WaitForMultipleObjects')]
private static extern int WaitForMultipleObjects(uint nCount, int[] lpHandles, int bWaitAll, int dwMilliseconds);
[DllImport('coredll.dll', EntryPoint = 'CloseHandle')]
private static extern int CloseHandle(int hObject);
static int hEvt;
static void Main(string[] args)
{
hEvt = CreateEvent(0, 1, 0, 0); // CreateEvent(NULL,TRUE,FALSE,NULL)
EventModify(hEvt, 2); // ResetEvent(hEvt);
Thread t = new Thread(excute);
t.Start();
Thread.Sleep(1000);
EventModify(hEvt, 3); // SetEvent(hEvt);
Thread.Sleep(10000);
EventModify(hEvt, 3); // SetEvent(hEvt);
CloseHandle(hEvt);
}
static void excute()
{
int i;
for (; ; )
{
i = WaitForSingleObject(hEvt, -1); // 無限等待
// i = WaitForSingleObject(hEvt, 1000); // 等待1秒
EventModify(hEvt, 2); // ResetEvent(hEvt);
Console.Write('event');
}
}
}
}

這里使用了API函數,所以需要添加引用

using System.Runtime.InteropServices;

通過CreateEvent創建一個事件,并獲得該事件句柄。這里參數一般使用(NULL,TRUE,FALSE,NULL),即(0, 1, 0, 0)

通過EventModify(hEvt, 2)將該事件的信號設置為無信號,該函數第一個參數為設置的事件句柄,第二個參數為2表示ResetEvent,第二個參數為3表示SetEvent。

hEvt = CreateEvent(0, 1, 0, 0); // CreateEvent(NULL,TRUE,FALSE,NULL)

EventModify(hEvt, 2); // ResetEvent(hEvt);

在線程中調用WaitForSingleObject函數等待事件,第一個參數為等待的事件句柄,第二個參數為等待的時間,如果為INFINITE即-1,表示一直等待,直到收到事件消息。該函數返回0表示接收到消息,返回0x102表示未接收到消息等待超時

i = WaitForSingleObject(hEvt, -1); // 無限等待

當主線程執行SetEvent即EventModify(hEvt, 3)時,掛起的副線程將被激活

EventModify(hEvt, 3); // SetEvent(hEvt);

在接收到信號的處理代碼里,需要重新將事件設置為未激活狀態,否則WaitForSingleObject函數將判定事件為激活狀態,不再發生等待

EventModify(hEvt, 2); // ResetEvent(hEvt);

在程序結束處,記得用CloseHandle關閉創建的事件

CloseHandle(hEvt);

使用API函數的事件響應與使用C#的事件類作用相同,因為使用了句柄做事件的標志,就可以與C的代碼進行交互,以英創ARM9系列嵌入式主板EM9161的CAN口數據接收線程為例。

設定一個線程用于CAN口的接收,創建一個事件用于通知線程關閉

private Thread revThread;

hCloseEvent = CreateEvent(0, 1, 0, 0); // CreateEvent(NULL,TRUE,FALSE,NULL)

打開CAN口后,通過COM組件接口函數獲得CAN的消息事件句柄

hEvent = CAN.CAN_GetRxEvent(hCAN);
hErr = CAN.CAN_GetErrorEvent(hCAN);

設定一個接收線程專門處理CAN口接收。
revThread = new Thread(new ThreadStart(BeginReceive));
threadStop = false;
revThread.Start(); // 啟動waitforMessage線程

在接收函數中,執行等待,直到有CAN口接收消息到來,或是接收到線程關閉的事件。

private void BeginReceive() // 客戶機狀態下接收數據線程
{
int[] handles = new int[2];
handles[0] = hCloseEvent;
handles[1] = hEvent;
int i;
bool bResult;
string revstr;
while (!threadStop)
{
// WaitForSingleObject(hEvent, 200);
i = WaitForMultipleObjects(2, handles, 0, -1); // handles里的兩個事件hEvent和hCloseEvent
// ….其他的處理代碼

}

}

這里使用了WaitForMultipleObjects來同時等待2個事件,第一個參數為等待的事件數。第二個參數為各事件的數組。第三個參數為FALSE即0表示當任何一個事件產生,該函數即返回,第三個參數為TRUE即1表示只有當所有事件都產生,該函數才返回。最后個參數為等待的時間。返回值為0x102表示超時,返回0-X表示接收的事件在數組中的位置,同時接收多個事件,返回的第一個事件在數組中的位置。

更詳細的完整代碼,請參考英創ARM9系列嵌入式主板EM9161的CAN事件接口例程。

8、等待線程

C#使用Thread類的Join函數來等待一個線程

using System;
using System.Threading;
namespace thread
{
class Program
{
static int i;
static void Main(string[] args)
{
Thread t = new Thread(excute);
t.Start();
for (i = 0; i < 10; i++)
{
Console.Write('2');
}
t.Join();
// t.Join(1000);
for (; ; )
{
Console.Write('2');
}
}
static void excute()
{
for (; ;)
{
Console.Write('1');
}
}
}
}

該函數不帶參數表示一直等待到線程結束,帶參數表示等待的時間,返回true表示線程已結束,返回false表示線程還在運行,只是超時返回。

在主函數關閉前,應使用Join函數來確保各支線程已完全關閉,否則會導致進程無法完全關閉。

9、其他

在關閉程序進程時,請確保關閉所有創建的線程,否則進程將無法完全關閉,并一直占用系統資源。在英創ARM9系列嵌入式主板程序開發中,可以結合VS自帶的遠程線程查看工具進行程序調試。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式主板
    +關注

    關注

    7

    文章

    6107

    瀏覽量

    37071
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    嵌入式單片機開發學習路徑

    學習C語言 C語言是嵌入式開發的基礎。掌握C語言的基本語法、指針、結構體、內存管理等內容是進入嵌入式開發的前提。 2. 硬件知識 2
    發表于 02-09 15:42

    什么是嵌入式應用開發?

    包括ARM7、ARM9、ARM11、PowerPC、MIPS等。這些處理器和編程語言的選擇取決于具體的硬件條件和開發需求?。 綜上所述,嵌入式應用開發是一個綜合性的技術領域,涉及硬件和軟件的緊密結合,廣泛應用于各種設備和
    發表于 01-12 16:13

    arm嵌入式主板優缺點

    Windows CE、Linux等主流的嵌入式操作系統。   ARM的優點   一、高可靠性、高穩定性:在工業控制領域,性能穩定可靠是自動控制基本的要求,ARM嵌入式主板有著很特殊的優勢。第一
    發表于 01-08 07:08

    從小白到大牛:Linux嵌入式系統開發的完整指南

    使用 C 語言(嵌入式開發主力語言)、POSIX 標準接口(文件 IO、進程、線程、信號量)。推薦通過 “溫度采集系統”“串口通信工具”等小型項目練手,重點掌握多
    發表于 12-16 10:42

    嵌入式應掌握的幾種能力

    1. 編程語言 基本掌握嵌入式必備的編程語言。C語言為主,C++為輔。在資源有限的情況下,大多數嵌入式
    發表于 12-08 06:05

    C語言在嵌入式開發中的應用

    語言可以確保實時系統中的任務能夠在規定的時間內完成,保證系統的穩定性和可靠性。 4、嵌入式網絡編程 隨著物聯網技術的飛速發展,
    發表于 11-21 08:09

    嵌入式和FPGA的區別

    。 在當今智能化時代,嵌入式系統和FPGA技術都是電子系統設計中的重要組成部分,但許多工程師和技術愛好者常常對兩者的區別和應用場景感到困惑
    發表于 11-19 06:55

    2025年最佳的嵌入式編程語言有哪些呢?

    嵌入式系統是現代科技不可或缺的一部分。它們存在于家用電器、汽車、住宅、醫院、商店等各個領域。它們與我們的社會緊密相連。選擇合適的語言來構建嵌入式系統對于成功至關重要。那么,2025年最
    的頭像 發表于 11-14 10:27 ?1410次閱讀
    2025年最佳的<b class='flag-5'>嵌入式</b><b class='flag-5'>編程</b>語言有哪些呢?

    嵌入式開發的關鍵點介紹

    嵌入式開發在現代科技中扮演著非常重要的角色。隨著物聯網的發展,嵌入式系統的需求也越來越大。嵌入式開發不僅需要開發人員具備深入的硬件知識和編程
    發表于 11-13 08:12

    嵌入式實時操作系統的特點

    。 低功耗和小尺寸:實時嵌入式操作系統通常要求運行時的資源占用較少,以適應嵌入式系統對功耗和尺寸的限制。 常見的實時嵌入式操作
    發表于 11-13 06:30

    盤點嵌入式就業所需要的技能有哪些?

    ,把握未來的職業機遇。 1.智能汽車行業: - 熟悉嵌入式編程語言,如C/C++、Python等。 - 掌握嵌入式
    發表于 08-11 15:43

    入行嵌入式應該怎么準備?

    知識: 一、C/C++編程C/C++是嵌入式系統
    發表于 08-06 10:34

    嵌入式和單片機,是同一個東西嗎?

    (RTOS)或沒有任何操作系統的裸機編程。軟件方面,嵌入式系統可能使用專門的編程語言,如C
    發表于 07-09 10:20

    嵌入式開發入門指南:從零開始學習嵌入式

    特定功能的計算機系統,廣泛應用于智能家居、工業控制、醫療設備、車載系統等領域。 2. 學習嵌入式開發的前置知識熟悉C語言編程掌握基本的數據結
    發表于 05-15 09:29

    嵌入式編程設計模式

    嵌入式編程設計模式,介紹如何使用設計模式為嵌入式系統創建高效且優化的C語言設計。 純分享貼,有需要可以直接下載附件獲取完整資料! (如
    發表于 04-15 14:47