網(wǎng)站首頁 編程語言 正文
線程間通信
我們看下面的圖
我們來看線程間通信的原理:線程(Thread B)和線程(Thread A)通信, 首先線程A 必須實(shí)現(xiàn)同步上下文對象(Synchronization Context), 線程B通過調(diào)用線程A的同步上下文對象來訪問線程A,所有實(shí)現(xiàn)都是在同步上下文中完成的.線程B有兩種方式來實(shí)現(xiàn)線程間的通信。
第一種:調(diào)用線程A的同步上下文對象,阻礙當(dāng)前線程,執(zhí)行紅色箭頭調(diào)用,直到黃色箭頭返回(同步上下文執(zhí)行完畢)才釋放當(dāng)前線程. (1->2->3->5)。
第二種:調(diào)用線程A的同步上下文對象(實(shí)際上是在開啟一個(gè)新線程去執(zhí)行,1->2->3->5) ,執(zhí)行紅色箭頭,但并不阻礙當(dāng)前線程(原有線程,1->4->5),綠色箭頭繼續(xù)執(zhí)行。
文章中將會通過下面幾個(gè)類來進(jìn)行介紹:
- ISynchronizeInvoke 接口
- SynchronizationContext 類
- AsyncOperation / AsyncOperationManager 類
1. ISynchronizeInvoke 接口
我們先來看下面一段異步的代碼(Window Form控件下有1個(gè)Button/1個(gè)Label),但點(diǎn)擊Button的時(shí)候,執(zhí)行異步調(diào)用,完成后,告訴Window Form的 Label控件Text屬性”Asynchronous End”。
在windows應(yīng)用窗體應(yīng)用程序中,對窗體上控件屬性的任何修改都必須在主線程中完成。不能從其他線程安全地訪問控件的方法和屬性。
ISynchronizeInvoke 接口來自.Net Framework 1.0,提供3個(gè)方法1個(gè)屬性:
- BeginInvoke / EndInvoke 方法 : 異步方法
- Invoke 方法 : 同步方法
- InvokeRequired 屬性 : 判讀來源的執(zhí)行線程
delegate void DoWork();
private void button1_Click(object sender, EventArgs e)
{
//更新狀態(tài),添加到Listbox 中
AddValue("Asynchronous Start.");
//使用委托來調(diào)用異步方法
DoWork work = DoWorkMethod;
work.BeginInvoke(OnWorkCallback, work);
}
void OnWorkCallback(IAsyncResult asyncResult)
{
DoWork work = asyncResult.AsyncState as DoWork;
if (work != null)
{
work.EndInvoke(asyncResult);
}
//(1)方法:調(diào)用Control控件的Invoke
//Action<string> asyncUpdateState = UpdateStatus; //Action<string> 介紹=> 附1
//Invoke(asyncUpdateState, "1:Asynchronous End.");
//(2)方法:直接在異步調(diào)用的線程下
UpdateStatus("2:Asynchronous End.");
}
void UpdateStatus(string input)
{
//把你需要通知的控件Control 賦值給ISynchronizeInvoke
//來實(shí)現(xiàn)線程間的通信
ISynchronizeInvoke async = this.listBoxStatus;
//使用(1)方法,InvokeRequired == false ,來源當(dāng)前(Window Form)主線程
if (async.InvokeRequired == false)
AddValue(input);
else// 使用(2)方法 == true ,來源其他線程(異步)
{
Action<string> action = new Action<string>(status =>
{
AddValue(status);
});
//調(diào)用ISynchronizeInvoke 提供的Invoke 同步方法,阻礙線程,直到調(diào)用結(jié)束
//也可以使用ISynchronizeInvoke 提供的異步BeginInvoke/EndInvoke方法來實(shí)現(xiàn)調(diào)用.
async.Invoke(action, new object[] { input });
}
}
void AddValue(string input)
{
this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
}
void DoWorkMethod()
{
Thread.Sleep(3000);//模擬耗時(shí)工作
}
在代碼中(UpdateStatus方法體內(nèi)),我們可以看到主要是在ISynchronizeInvoke async = this.listBoxStatus;實(shí)現(xiàn)了線程間的通信,MSDN的解釋” 實(shí)現(xiàn)此接口的對象可以接收事件已發(fā)生的通知,并且可以響應(yīng)有關(guān)該事件的查詢”. 并使Window Form(主線程) 下的ListBox 控件和來自異步方法(另外一個(gè)線程)的建立了通道。
InvokeRequired 判斷線程的來源。
如果使用(1)方法,來源于Window Form 自身Control 的Invoke方法, InvokeRequired將返回false; 來源另外線程(異步)。
如果使用(2)返回true.同時(shí)ISynchronizeInvoke 提供了異步(BeginInvoke+EndInvok)和同步方法(Invoke)來實(shí)現(xiàn)線程間通信.Invoke 就是最上面的圖1 所示的第一種 / BeginInvoke+EndInvok 是第二種。
2. SynchronizationContext 類
相比ISynchronizeInvoke 接口,SynchronizationContext 類(來自.Net Framework 2.0)提供了更多的方法來操作同步上下文對象,實(shí)現(xiàn)線程間通信.在上面的例子中SynchronizationContext類中將由 Post/Send 方法來實(shí)現(xiàn)。
反編譯后我們看到:
public virtual void Post(SendOrPostCallback d, object state)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);
}
public virtual void Send(SendOrPostCallback d, object state)
{
d(state);
}
- Send = ISynchronizeInvoke 中的Invoke 同步調(diào)用.圖1中的第一種
- Post = ISynchronizeInvoke 中的BeginInvoke + EndInvoke異步調(diào)用. 圖1中的第二種
SynchronizationContext 類舉例(在WinForm 下編程)
delegate void DoWork();
private void button1_Click(object sender, EventArgs e)
{
//System.Windows.Forms.Form 自動的創(chuàng)建默認(rèn)的同步上下文對象,
//直接的獲取當(dāng)前的同步上下文對象
SynchronizationContext context = SynchronizationContext.Current;
//更新狀態(tài),添加到Listbox 中
AddValue<string>("Asynchronous Start.");
//使用委托來調(diào)用異步方法
DoWork work = DoWorkMethod;
work.BeginInvoke(OnWorkCallback, context);
}
void OnWorkCallback(IAsyncResult asyncResult)
{
AsyncResult async = (AsyncResult)asyncResult;
DoWork work = (DoWork)async.AsyncDelegate;
work.EndInvoke(asyncResult);
//更新狀態(tài)
UpdateStatus("Asynchronous End.", asyncResult.AsyncState);
}
void UpdateStatus(object input,object syncContext)
{
//獲取主線程(Window Form)中同步上下文對象
SynchronizationContext context = syncContext as SynchronizationContext;
//使用SynchronizationContext 類中異步Post 方法
SendOrPostCallback callback = new SendOrPostCallback(p => {
AddValue<object>(p);
});
context.Post(callback, input);//Post 為異步,Send 為同步
}
void AddValue<T>(T input)
{
this.listBoxStatus.Items.Add(string.Format("[(#{2}){0}]Context is null:{1}", input, Thread.CurrentContext == null, Thread.CurrentThread.ManagedThreadId));
}
void DoWorkMethod()
{
Thread.Sleep(3000);//模擬耗時(shí)工作
}
上面我們已經(jīng)說過在主線程中System.Windows.Forms.Form 自動的創(chuàng)建默認(rèn)的同步上下文對象, 這時(shí)候我們把當(dāng)前的同步上下文對象通過參數(shù)的形式賦值到異步線程中,調(diào)用Post 方法來實(shí)現(xiàn), Post 方法接收 SendOrPostCallback 委托和額外object state參數(shù),在Post方法體內(nèi)調(diào)用線程池的線程來實(shí)現(xiàn)(Code2.1).當(dāng)然我們也可以直接使用Send方法。
下面我們看看線程中的代碼(在Console 下編程)。
static class Program
{
static void Main()
{
Output("Main Thread Start.");
//為主線程創(chuàng)建Synchronization Context
var context = new SynchronizationContext();
//開始一個(gè)新線程
Thread threadB = new Thread(work);
threadB.Start(context);
Console.Read();
}
static void work(object context)
{
Output("Thread B");
//獲取主線程中的同步上下文對象
SynchronizationContext sc = context as SynchronizationContext;
//異步的方式和主線程通信,并發(fā)送"Hello World".
sc.Post(new SendOrPostCallback(p =>
{
Output(p);
}), "Hello World");
}
static void Output(object value)
{
Console.WriteLine("[ThreadID:#{0}]{1}", Thread.CurrentThread.ManagedThreadId, value);
}
}
在主線程中因?yàn)闆]有同步上下文對象,所以開始我們new SynchronizationContext(); 對象,其他和上面基本一樣.此例說明了Post 是開啟新線程(線程池)運(yùn)行的。
3. AsyncOperation / AsyncOperationManager 類
AsyncOperation / AsyncOperationManager 類是SynchronizationContext 類的進(jìn)一步封裝和實(shí)現(xiàn), AsyncOperationManager在創(chuàng)建AsyncOperation對象的時(shí)候會取得當(dāng)前線程的同步上下文對象,并存儲在AsyncOperation之中,使我們訪問同步上下文對象更加容易。
public class MySynchronizedClass
{
private AsyncOperation operation;
public event EventHandler somethingHappened;
public MySynchronizedClass()
{
//創(chuàng)建AsyncOperation 對象,并把當(dāng)前線程的同步上下文保持到AsyncOperation中.
operation = AsyncOperationManager.CreateOperation(null);
Thread workerThread = new Thread(new ThreadStart(DoWork));
workerThread.Start();
}
private void DoWork()
{
SendOrPostCallback callback = new SendOrPostCallback(state =>
{
EventHandler handler = somethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
});
operation.Post(callback, null);
//注意1
operation.OperationCompleted();
}
}
AsyncOperation類中實(shí)現(xiàn)了OperationCompleted的方法. SynchronizationContext 類中這個(gè)方法是沒有具體的代碼實(shí)現(xiàn)的。
原文鏈接:https://www.cnblogs.com/springsnow/p/11195710.html
相關(guān)推薦
- 2022-08-28 虛擬機(jī)ubuntu通過fdisk命令擴(kuò)充硬盤容量,分區(qū)簡單說明
- 2022-11-05 Nginx監(jiān)控模塊(vts模塊)詳解_nginx
- 2022-11-16 創(chuàng)建Go工程化項(xiàng)目布局詳解_Golang
- 2022-09-25 git問題:“ unable to auto-detect email address”或 “***
- 2023-12-08 table 單元格垂直居中
- 2022-04-11 Linux系統(tǒng)?Centos7.4手動在線升級到Centos7.7_Linux
- 2022-10-13 Python詳細(xì)介紹模型封裝部署流程_python
- 2022-01-22 記一次線上sql優(yōu)化從9s到400ms的過程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支