与非CCR代码互操作
原文鏈接
線程套間約束
當與某些遺留的Windows組件,特別是COM對象交互時需要特定的線程套件策略。甚至最近的框架,例如.net WinForms,也需要在運行WinForm的線程上應用單線程套間(SingleThreadedApartment)策略。
CCR可以輕松的承載STA組件或者與它互操作:組件應該創建一個只有一個線程的CCR Dispatcher實例,并且在Dispatcher的構造函數中指定線程套間策略。DispatcherQueue實例就可以在與需要和遺留代碼交互的地方使用這個dispatcher來激活處理函數(activating handlers)。這些處理函數就可以安全的訪問COM或者WinForm對象,同時對其他的CCR組件隱藏它們的STA關系,以便其他CCR組件可以簡單的投遞元素到常規的CCR ports而不需要關心port上的處理函數使用的是什么dispatcher。
CCR WinFrom適配庫(Ccr.Adapters.Winforms.dll)是一個在CCR中運行.net WinForm的便利方法。
與應用的主線程協調
CCR軟件組件經常在一個CLR應用的上下文中中執行,例如一個獨立執行程序。.net運行時使用一個操作系統線程啟動一個程序,當線程退出時終止程序。由于CCR應用是異步、并發的,所以它們在沒有消息被發送時處于非激活狀態,并且幾乎不會阻塞任何線程。CCR Dispatcher將保持線程在一種高效的休眠狀態,但是如果其它的線程被作為后臺線程創建,應用程序將會退出,那么CCR還在執行。
一個與CLR啟動的同步世界接口的常見模式是使用System.Threading.AutoResetEvent來阻塞應用的主線程,直到CCR應用完成。AutoResetEvent事件可以被任何CCR處理函數觸發。
例25.
void?InteropBlockingExample(){
????//?create?OS?event?used?for?signalling
????AutoResetEvent?signal?=?new?AutoResetEvent(false);
????//?schedule?a?CCR?task?that?will?execute?in?parallel?with?the?rest?of
????//?this?method
????Arbiter.Activate(
????????_taskQueue,
????????new?Task<AutoResetEvent>(signal,?SomeTask)
????);
????//?block?main?application?thread?form?exiting
????signal.WaitOne();
}
void?ThrottlingExample()
{
????int?maximumDepth?=?10;
????Dispatcher?dispatcher?=?new?Dispatcher(0,?"throttling?example");
????DispatcherQueue?depthThrottledQueue?=?new?DispatcherQueue("ConstrainQueueDepthDiscard",
??????????dispatcher,
??????????TaskExecutionPolicy.ConstrainQueueDepthDiscardTasks,
??????????maximumDepth);
????Port<int>?intPort?=?new?Port<int>();
????Arbiter.Activate(depthThrottledQueue,
???????Arbiter.Receive(true,?intPort,
???????delegate(int?i)
???????{
???????????//?only?some?items?will?be?received?since?throttling?will?discard?most?of?them
???????????Console.WriteLine(i);
???????})
????);
????//?post?items?as?fast?as?possible?so?that?the?depth?policy?is?activated?and?discards
????//?all?the?oldest?items?in?the?dispatcher?queue
????for?(int?i?=?0;?i?<?maximumDepth?*?100000;?i++)
????{
????????intPort.Post(i);
????}
}
///?<summary>
///?Handler?that?executes?in?parallel?with?main?application?thread
///?</summary>
///?<param?name="signal"></param>
void?SomeTask(AutoResetEvent?signal)
{
????try
????{
????????for?(int?i?=?0;?i?<?1000000;?i++)
????????{
????????????int?k?=?i?*?i?/?10;
????????}
????}
????finally
????{
????????//?done,?signal?main?application?thread
????????signal.Set();
????}
} 在上面的例子中,我們演示了一個使用操作系統事件來阻塞應用程序主線程的小例子。
簡化.NET異步編程模式
CCR可以用于任何實現了異步變成模型模式的.net類型。它實際上極大的簡化了異步模式,并且當用于C#時,完全不再需要delegate和接續傳遞(continuation passing)。CCR迭帶器調度支持允許你直接返回并繼續(yield)掛起的I/O操作并且實現的易讀的代碼和過去只能在同步代碼中實現的模式。
例27.
IEnumerator<ITask>?CcrReadEnumerator(string?filename)
{
????var?resultPort?=?new?Port<IAsyncResult>();
????//?stage?1:?open?file?and?start?the?asynchronous?operation
????using?(FileStream?fs?=?new?FileStream(filename,?
????????FileMode.Open,?FileAccess.Read,?FileShare.Read,?8192,?FileOptions.Asynchronous))
????{
????????Byte[]?data?=?new?Byte[fs.Length];
????????fs.BeginRead(data,?0,?data.Length,?resultPort.Post,?null);????
????????//?stage?2:?suspend?execution?until?operation?is?complete
????????yield?return?Arbiter.Receive(false,?resultPort,?delegate?{?});
????????//?stage?3:?retrieve?result?of?operation?just?by?assigned?variable?to?CCR?port
????????var?ar?=?(IAsyncResult)resultPort;
????????try
????????{???Int32?bytesRead?=?fs.EndRead(ar);?}
????????catch
????????{???
????????????//?handle?I/O?exception?
????????}
????????ProcessData(data);
????}
} 例子27演示了CCR如何使用文件流的異步編程模型BeginRead/EndRead方法而又不需要傳遞delegate。取而代之的是,我們提供一個CCR Port的Post方法,所以異步結果被直接投遞到一個CCR Port。代碼返回并繼續在一個port上進行接受操作。yield return語句允許我們編寫邏輯上順序的代碼而不需要使用一個操作系統線程。代碼保留了異步的可伸縮性和overlapped操作,但是讀起來就像是同步、順序的代碼。
例28 ///?<summary>
///?Read?from?one?stream?into?a?Http?request?stream,?asynchronously
///?</summary>
public?virtual?IEnumerator<ITask>?UploadHttpStream(string?contentUrl,
????Stream?contentStream,?PortSet<HttpStatusCode,?Exception>?resultPort)
{
????//?Create?HTTP?request
????HttpWebRequest?webRequest?=?(HttpWebRequest)WebRequest.Create(contentUrl);
????webRequest.Method?=?"POST";
????HttpStatusCode?status?=?HttpStatusCode.OK;
????Exception?ex?=?null;
????using?(Stream?requestStream?=?webRequest.GetRequestStream())
????{
????????byte[]?readBuffer?=?new?byte[1024];
????????int?bytesRead?=?-1;
????????//?With?CCR?and?iterators?you?can?do?loops?and?asynchronous?I/O
????????do
????????{
????????????//?use?CCR?stream?adapter?(or?a?custom?APM?adapter)?to?schedule?operation
????????????var?ioResultPort?=?StreamAdapter.Read(contentStream,?readBuffer,?0,?1024);
????????????//?yield?to?result?(success?or?failure)
????????????yield?return?(Choice)ioResultPort;
????????????//?check?for?error
????????????ex?=?ioResultPort;
????????????if?(ex?!=?null)
????????????{
????????????????resultPort.Post(ex);
????????????????//?exit?on?error
????????????????yield?break;
????????????}
????????????bytesRead?=?ioResultPort;
????????????var?writeResultPort?=?StreamAdapter.Write(requestStream,?readBuffer,?0,?bytesRead);
????????????//?yield?to?write?operation
????????????yield?return?(Choice)writeResultPort;
????????????//?check?for?write?error
????????????ex?=?writeResultPort;
????????????if?(ex?!=?null)
????????????{
????????????????resultPort.Post(ex);
????????????????yield?break;
????????????}
????????}?while?(bytesRead?>?0);
????????requestStream.Flush();
????}
????//?Use?built-in?CCR?adapter?for?reading?HTTP?response
????var?webResultPort?=?WebRequestAdapter.ReadResponse(webRequest,?_taskQueue);
????//?yield?to?web?response?operation
????yield?return?(Choice)webResultPort;
????//?check?for?any?exceptions
????GetErrorDetails((Exception)webResultPort,?out?status);
????resultPort.Post(status);
} 例子28展示了一個更復雜的異步變成模型交互:一個CCR迭帶器被調度來從一個流異步的讀取數據,然后再異步的把數據寫到一個HTTP請求流中。值得注意的是,CCR可以表達內部包含異步操作的while和for循環。
參考
MSDN Magazine: Concurrent Affairs -- Concurrency and Coordination Runtime
轉載于:https://www.cnblogs.com/ncindy/archive/2007/12/17/1003748.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的与非CCR代码互操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ECS框架学习
- 下一篇: 在Windows中为文件添加“可执行”权