基本概念
線程
- 被定義為程序的執行路徑,也叫執行單元
- 線程是輕量級進程;使用線程節省了 CPU 周期的浪費,同時提高了應用程序的效率
進程
- 是Windows系統中的一個基本概念,它包含著一個運行程序所需要的資源。一個正在運行的應用程序在操作系統中被視為一個進程
- 一個進程可以包括一個或多個線程, 注:至少得有一個線程
- 進程之間是相對獨立的,一個進程無法訪問另一個進程的數據
查看當前系統中的進程
打開任務管理器,查看當前運行的進程
編輯
查看當前系統中的線程
在任務管理器里面查詢當前總共運行的線程數
編輯
并行與串行(異步與同步)
- 并行(異步): 多個線程同時執行任務
- 舉例:小明在燒開水的同時去洗菜了
- 串行(同步): 一個任務執行完后才能執行下一個
- 舉例:小明在燒開水,等開水燒開后再去洗菜
線程的生命周期
- 新建 :當線程實例被創建但 Start 方法未被調用時的狀況
- 就緒 :當線程準備好運行并等待 CPU 調度
- 不可運行 :下面的幾種情況下線程是不可運行的:
- 已經調用 Sleep 方法
- 已經調用 Wait 方法
- 通過 I/O 操作阻塞
- 死亡狀態 :當線程已完成執行或已中止時的狀況
主線程
- 一個進程可以包含若干個線程,在進程入口執行的 第一個線程被視為這個進程的主線程 。
- 在 C# 中,都是以Main()方法作為入口的,當調用此方法時系統就會自動創建一個主線程。
- 在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創建并訪問多線程應用程序中的單個線程
- 可以使用 Thread 類的 CurrentThread 屬性訪問線程。
舉例:主線程執行
internal class ThreadTest
{
static void Main(string[] args)
{
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("線程ID是:{0},線程名稱是:{1}", th.ManagedThreadId, th.Name);
}
}
輸出結果
線程ID是:1,線程名稱是:MainThread
**多線程的創建與管理 **
創建
- 線程是通過擴展 Thread 類創建的,然后在構造方法中傳入委托對象。擴展的 Thread 類調用 Start() 方法來開始子線程的執行
- **子線程不需要傳參使用 **ThreadStart
internal class ThreadTest
{
static void Main(string[] args)
{
// 創建兩個子線程
Thread t1 = new Thread(new ThreadStart(PrintStr));
Thread t2 = new Thread(new ThreadStart(PrintStr));
t1.Start();
t2.Start();
}
private static void PrintStr()
{
Thread th = Thread.CurrentThread;
Console.WriteLine("線程ID是:{0}", th.ManagedThreadId);
}
}
輸出結果
線程ID是:7
線程ID是:6
通過ThreadStart 源碼,可以看到它其實是一個委托
編輯
internal class ThreadTest
{
static void Main(string[] args)
{
// 創建兩個子線程
Thread t1 = new Thread(new ParameterizedThreadStart(PrintStrParam));
Thread t2 = new Thread(new ParameterizedThreadStart(PrintStrParam));
t1.Start("我是有參數1");
t2.Start("我是有參數2");
}
private static void PrintStrParam(Object obj)
{
Thread th = Thread.CurrentThread;
Console.WriteLine("線程ID是:{0},參數是:{1}", th.ManagedThreadId,obj);
}
}
輸出結果
線程ID是:6,參數是:我是有參數1
線程ID是:7,參數是:我是有參數2
線程的管理與銷毀
- Thread 類提供了各種管理線程的方法,下面演示sleep() 方法的使用,用于在一個特定的時間暫停線程
- Abort() 方法用于銷毀線程;通過拋出 threadabortexception 在運行時中止線程。這個異常不能被捕獲,如果有 finally 塊,控制會被送至 finally 塊。 注:這個方法被標記過時了,雖然依舊可以使用,但推薦使用 CancellationToken 來代替
internal class ThreadTest
{
static void Main(string[] args)
{
// 創建兩個子線程
Thread t1 = new Thread(new ThreadStart(printSleep));
t1.Start();
// 主線程睡眠 1 秒
Thread.Sleep(1000);
// 銷毀線程
try
{
t1.Abort();
}
catch (ThreadAbortException e)
{
Console.WriteLine("進catch了嗎???");
}
finally
{
Console.WriteLine("進finally了嗎???");
}
}
private static void printSleep()
{
for (int i = 0; i < 10; i++)
{
// 睡眠 500 毫秒
Thread.Sleep(500);
Console.WriteLine("輸出數字:{0}", i);
}
}
}
輸出結果
輸出數字:0
Unhandled exception. 輸出數字:1
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
輸出數字:2
進finally了嗎???
線程同步與鎖
- 所謂同步:是指在某一時刻只有一個線程可以訪問變量。
- 如果不能確保對變量的訪問是同步的,就會產生錯誤。比如:兩個人同時賣一個倉庫中的同種 手機,如果不控制就可能出現 超賣現象 (即賣出的大于庫存的)
- c#為同步訪問變量提供了一個非常簡單的方式,即使用c#語言的關鍵字 **Lock**,它可以把一段代碼定義為互斥段,互斥段在一個時刻內只允許一個線程進入執行
lock
塊語法:
- 需要注意,傳給**
lock
塊**的參數不能是值類型和string
類型,必須是除了string
外的引用類型,而且這個引用類型對象必須是所有線程都能訪問到的,否則鎖不住。 - 如果你想保護一個類的實例,一般地,你可以使用this;
- 如果你想保護一個靜態變量(如互斥代碼段在一個靜態方法內部),一般使用類名就可以了
- 也可以單獨創建一個
object
對象來作為指定的鎖對象
語法如下:
lock(expression)
{
// 代碼邏輯
}
加鎖前案例
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創建兩個子線程
Thread t1 = new Thread(new ThreadStart(phone.SalePhone));
Thread t2 = new Thread(new ThreadStart(phone.SalePhone));
t1.Start();
t2.Start();
}
}
public class PhoneSale
{
// 數量
private int num = 1;
public void SalePhone()
{
if (num > 0)
{
Thread.Sleep(100);
num--;
Console.WriteLine("賣出一部手機,還剩下 {0} 個",num);
}
else
{
Console.WriteLine("賣完了....");
}
}
}
輸出結果
賣出一部手機,還剩下 0 個
賣出一部手機,還剩下 -1 個
**加鎖后案例
**
internal class ThreadTest
{
static void Main(string[] args)
{
PhoneSale phone=new PhoneSale();
// 創建兩個子線程
Thread t1 = new Thread(new ThreadStart(phone.SalePhone));
Thread t2 = new Thread(new ThreadStart(phone.SalePhone));
t1.Start();
t2.Start();
}
}
public class PhoneSale
{
// 數量
private int num = 1;
public void SalePhone()
{
lock (this)
{
if (num > 0)
{
Thread.Sleep(100);
num--;
Console.WriteLine("賣出一部手機,還剩下 {0} 個", num);
}
else
{
Console.WriteLine("賣完了....");
}
}
}
}
輸出結果
賣出一部手機,還剩下 0 個
賣完了....
多線程的優缺點
優點
- 可以同時完成多個任務,使程序的響應速度更快
- 多線程技術解決了多部分代碼同時執行的需求,能夠更好的利用cpu的資源
- 可以設置每個任務的優先級以優化程序性能
缺點
- 線程需要占用內存,線程越多,占用內存也越多
- 多線程需要協調和管理,所以需要占用CPU時間以便跟蹤線程
- 線程之間對共享資源的訪問會相互影響,必須解決爭用共享資源的問題
- 線程太多會導致控制太復雜
為什么程序可以多線程執行呢? 程序中的多線程與CPU的多線程有什么關系?
-
目前電腦都是多核多CPU的,一個CPU在同一時刻只能運行一個線程,但是多個CPU在同一時刻就可以運行多個線程。
-
線程的最大并行數量上限是CPU核心的數量,但是,往往電腦運行的線程的數量遠大于CPU核心的數量,所以還是需要CPU時間片的切換
-
CPU運行速度太快,硬件處理速度跟不上,所以操作系統進行分 ** 時間片
管理** 。這樣,從宏觀角度來說是多線程并發的,因為CPU速度太快,察覺不到,看起來是同一時刻執行了不同的操作
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
cpu
+關注
關注
68文章
10868瀏覽量
211844 -
WINDOWS
+關注
關注
3文章
3546瀏覽量
88734 -
程序
+關注
關注
117文章
3787瀏覽量
81066
發布評論請先 登錄
相關推薦
Java多線程的用法
本文將介紹一下Java多線程的用法。 基礎介紹 什么是多線程 指的是在一個進程中同時運行多個線程,每個線程都可以獨立執行不同的任務或操作。 與單線程
多線程技術在串口通信中的應用
首先介紹了多線程技術的基本原理,然后討論了多線程技術在串口通信中的應用,并給出了實現的方法和步驟。關鍵詞:多線程;串口通信;事件
發表于 09-04 09:10
?18次下載
多線程與聊天室程序的創建
多線程程序的編寫,多線程應用中容易出現的問題。互斥對象的講解,如何采用互斥對象來實現多線程的同步。如何利用命名互斥對象保證應用程序只有一個實例運行。應用多線程編寫網絡聊天室程序。
發表于 05-16 15:22
?0次下載
linux多線程編程技術
1 引言 線程(thread)技術早在60年代就被提出,但真正應用多線程到操作系統中去,是在80年代中期,solaris是這方面的佼佼者。傳統的 Unix也支持線程的概念,但是在一個進程
發表于 10-24 16:01
?5次下載
多線程好還是單線程好?單線程和多線程的區別 優缺點分析
摘要:如今單線程與多線程已經得到普遍運用,那么到底多線程好還是單線程好呢?單線程和多線程的區別又
發表于 12-08 09:33
?8.1w次閱讀
mfc多線程編程實例及代碼,mfc多線程間通信介紹
摘要:本文主要以MFC多線程為中心,分別對MFC多線程的實例、MFC多線程之間的通信展開的一系列研究,下面我們來看看原文。
發表于 12-08 15:23
?1.8w次閱讀
什么是多線程編程?多線程編程基礎知識
摘要:多線程編程是現代軟件技術中很重要的一個環節。要弄懂多線程,這就要牽涉到多進程。本文主要以多線程編程以及多線程編程相關知識而做出的一些結論。
發表于 12-08 16:30
?1.3w次閱讀
多線程如何保證數據的同步
多線程編程是一種并發編程的方法,意味著程序中同時運行多個線程,每個線程可獨立執行不同的任務,共享同一份數據。由于多線程并發執行的特點,會引發數據同步的問題,即保證多個
mfc多線程編程實例
(圖形用戶界面)應用程序的開發。在這篇文章中,我們將重點介紹MFC中的多線程編程。 多線程編程在軟件開發中非常重要,它可以實現程序的并發執行,提高程序的效率和響應速度。MFC提供了豐富的多線程支持,可以輕松地實現
評論