日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

vb.net2019-多线程并行计算(4)

發(fā)布時(shí)間:2025/3/12 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 vb.net2019-多线程并行计算(4) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

三、棧內(nèi)存

1、每個(gè)WINDOWS都有一個(gè)棧基址和棧限址,二者合在一起表示棧的有效內(nèi)存范圍。棧限址不是固定的,程序需要更多內(nèi)存空間里,棧限址沒(méi)有超過(guò)保留的棧內(nèi)存范圍,則可以要求更多的內(nèi)存頁(yè)

2、在棧限址外是棧的守護(hù)頁(yè),當(dāng)訪問(wèn)到守護(hù)頁(yè)時(shí),會(huì)引發(fā)STATUS_GUARD_PAGE_VIOLATION異常,當(dāng)異常發(fā)生后,操作系統(tǒng)捕捉后,提交下一頁(yè)內(nèi)存,然后將其做為新的守護(hù)頁(yè),這相當(dāng)于分配了一個(gè)新的頁(yè)給程序訪問(wèn),就是棧動(dòng)態(tài)增長(zhǎng)。
具體機(jī)制是當(dāng)訪問(wèn)了帶PAGE_GUARD 屬性的內(nèi)存時(shí),操作系統(tǒng)意識(shí)到當(dāng)前棧內(nèi)存已經(jīng)用完,因?yàn)闂?nèi)存的下一頁(yè)就是守護(hù)頁(yè),操作系統(tǒng)馬上清除守護(hù)頁(yè)的PAGE_GUARD 標(biāo)志,將其用于補(bǔ)充當(dāng)前的棧內(nèi)存,同時(shí)申請(qǐng)一個(gè)新的內(nèi)存頁(yè)做為守護(hù)頁(yè),隨著新守護(hù)頁(yè)的不斷申請(qǐng),越來(lái)越多的老守護(hù)頁(yè)加入當(dāng)前棧空間,這就是動(dòng)態(tài)增長(zhǎng)

3、從MSDN中可以查到
A guard page provides a one-shot alarm for memory page access. This can be useful for an application that needs to monitor the growth of large dynamic data structures. For example, there are operating systems that use guard pages to implement automatic stack checking.

To create a guard page, set the PAGE_GUARD page protection modifier for the page. This value can be specified, along with other page protection modifiers, in the VirtualAlloc, VirtualAllocEx, VirtualProtect, and VirtualProtectEx functions. The PAGE_GUARD modifier can be used with any other page protection modifiers, except PAGE_NOACCESS.

If a program attempts to access an address within a guard page, the system raises a STATUS_GUARD_PAGE_VIOLATION (0x80000001) exception. The system also clears the PAGE_GUARD modifier, removing the memory page’s guard page status. The system will not stop the next attempt to access the memory page with a STATUS_GUARD_PAGE_VIOLATION exception.

If a guard page exception occurs during a system service, the service fails and typically returns some failure status indicator. Since the system also removes the relevant memory page’s guard page status, the next invocation of the same system service won’t fail due to a STATUS_GUARD_PAGE_VIOLATION exception (unless, of course, someone reestablishes the guard page).

The following short program illustrates the behavior of guard page protection.

保護(hù)頁(yè)提供了一個(gè)內(nèi)存頁(yè)的訪問(wèn)警告,對(duì)應(yīng)用程序監(jiān)視,操作系統(tǒng)用它來(lái)實(shí)現(xiàn)棧的自動(dòng)檢查
在 VirtualAlloc, VirtualAllocEx, VirtualProtect, and VirtualProtectEx 函數(shù)中可以定義這個(gè)參數(shù)

目前我們使用VB.NET進(jìn)行多線程編程,使用的是.NET的CLR托管線程,CLR使用了SetThreadStackGuarantee來(lái)以更大的增量來(lái)遞增棧限址,這個(gè)API指定了守護(hù)區(qū)域大小,如果將大小設(shè)置為0,則返回當(dāng)前的守護(hù)區(qū)域大小。

3、運(yùn)用stacktrace類實(shí)現(xiàn)線程棧回溯跟蹤

代碼如下:

Imports System Imports System.Threading Imports System.Diagnostics.StackTraceModule Module1Sub Main()Dim main_x As Integermain_x = 5Call sub1(main_x)End SubPrivate Sub sub1(sub1_x As Integer)Dim jg As Integerjg = sub1_x * sub1_xCall sub2(jg)End SubPrivate Sub sub2(sub2_x As Integer)Dim jg As Integerjg = sub2_x * 2jg = jg * jgDim st As New StackTrace(True)Console.WriteLine(" 棧跟蹤: {0}", _st.ToString())Dim i As IntegerFor i = 0 To st.FrameCount - 1Dim sf As StackFrame = st.GetFrame(i)Console.WriteLine()Console.WriteLine("回溯調(diào)用棧, 方法: {0}", _sf.GetMethod())Console.WriteLine("回溯調(diào)用棧, 行號(hào) : {0}", _sf.GetFileLineNumber())Next iEnd SubEnd Module

下面這句定義了StackTrace 類的新實(shí)例,實(shí)現(xiàn)線程棧跟蹤

StackTrace 是使用調(diào)用方的當(dāng)前線程創(chuàng)建的,參數(shù)含義如下:

如果為 true,則捕獲文件名、行號(hào)和列號(hào);否則為 false。

Dim st As New StackTrace(True)

3、運(yùn)用stacktrace類實(shí)現(xiàn)線程棧回溯跟蹤

代碼如下:

Imports System Imports System.Threading Imports System.Diagnostics.StackTraceModule Module1Sub Main()Dim main_x As Integermain_x = 5Call sub1(main_x)End SubPrivate Sub sub1(sub1_x As Integer)Dim jg As Integerjg = sub1_x * sub1_xCall sub2(jg)End SubPrivate Sub sub2(sub2_x As Integer)Dim jg As Integerjg = sub2_x * 2jg = jg * jgDim st As New StackTrace(True)Console.WriteLine(" 棧跟蹤: {0}", _st.ToString())Dim i As IntegerFor i = 0 To st.FrameCount - 1Dim sf As StackFrame = st.GetFrame(i)Console.WriteLine()Console.WriteLine("回溯調(diào)用棧, 方法: {0}", _sf.GetMethod())Console.WriteLine("回溯調(diào)用棧, 行號(hào) : {0}", _sf.GetFileLineNumber())Next iEnd SubEnd Module

下面這句定義了StackTrace 類的新實(shí)例,實(shí)現(xiàn)線程棧跟蹤

StackTrace 是使用調(diào)用方的當(dāng)前線程創(chuàng)建的,參數(shù)含義如下:

如果為 true,則捕獲文件名、行號(hào)和列號(hào);否則為 false。

Dim st As New StackTrace(True)

4、棧溢出

1)溢出情況

a)線程試圖提交比保留大小更多的棧內(nèi)存頁(yè)

b)沒(méi)有物理內(nèi)存也沒(méi)有虛擬內(nèi)存可供提交更多的守護(hù)頁(yè)

2、棧溢出后還想繼續(xù)運(yùn)行程序,必須重置守護(hù)頁(yè),可以使用CRT的_resetstkoflw。

不過(guò)對(duì)于大的數(shù)據(jù),可以考慮將某些數(shù)據(jù)移到堆中。堆棧是有限的,甚至在用戶模式下也是如此,如果無(wú)法提交堆棧頁(yè),會(huì)導(dǎo)致堆棧溢出異常。_resetstkoflw 函數(shù)可以將系統(tǒng)從堆棧溢出的情況恢復(fù)為正常,從而使程序得以繼續(xù)運(yùn)行,而不會(huì)由于出現(xiàn)異常錯(cuò)誤而失敗。如果未調(diào)用 _resetstkoflw 函數(shù),則在上一個(gè)異常后不會(huì)顯示保護(hù)頁(yè)。當(dāng)下次發(fā)生堆棧溢出時(shí),根本不會(huì)顯示異常,進(jìn)程將在沒(méi)有任何警告的情況下終止。

System.Runtime.CompilerServices.RuntimeHelpers在線程棧空間的探查方面有很大的作用

下面這是這個(gè)類的常用方法

EnsureSufficientExecutionStack 確保剩余的堆棧空間足夠大,可以執(zhí)行一般的 .NET Framework 函數(shù)。
Equals(Object, Object) 確定指定的 Object 實(shí)例是否被視為相等。
ExecuteCodeWithGuaranteedCleanup 使用一個(gè) Delegate 執(zhí)行代碼,同時(shí)使用另一個(gè) Delegate 在異常情況下執(zhí)行附加代碼。
GetHashCode(Object) 用作特定類型的哈希函數(shù),適合在哈希算法和數(shù)據(jù)結(jié)構(gòu)(如哈希表)中使用。
GetObjectValue 將值類型裝箱。
InitializeArray 提供從存儲(chǔ)在模塊中的數(shù)據(jù)初始化數(shù)組的快速方法。
PrepareConstrainedRegions 將代碼體指定為受約束的執(zhí)行區(qū)域 (CER)。
PrepareConstrainedRegionsNoOP 指定代碼體為受約束的執(zhí)行區(qū)域 (CER),而不執(zhí)行任何探測(cè)。
PrepareContractedDelegate 提供應(yīng)用程序用來(lái)動(dòng)態(tài)準(zhǔn)備 AppDomain 事件委托的方法。
PrepareDelegate 指示應(yīng)準(zhǔn)備指定委托以包含在受約束的執(zhí)行區(qū)域 (CER) 中。
PrepareMethod(RuntimeMethodHandle) 準(zhǔn)備一個(gè)要包含在受約束的執(zhí)行區(qū)域 (CER) 中的方法。
PrepareMethod(RuntimeMethodHandle, RuntimeTypeHandle()) 準(zhǔn)備一個(gè)要包含在受約束的執(zhí)行區(qū)域 (CER) 中的具有指定實(shí)例化的方法。
ProbeForSufficientStack 探測(cè)某個(gè)數(shù)量的堆棧空間,以確保不會(huì)在后續(xù)的代碼塊內(nèi)發(fā)生堆棧溢出(假設(shè)您的代碼僅使用有限適中的堆棧空間)。 建議使用受約束的執(zhí)行區(qū)域 (CER),而不使用此方法。
RunClassConstructor 運(yùn)行指定的類構(gòu)造函數(shù)方法。
RunModuleConstructor 運(yùn)行指定的模塊構(gòu)造函數(shù)方法。

其中比較常用的是

ProbeForSufficientStack 和PrepareConstrainedRegions

從MSDN中可看出以下細(xì)節(jié):

1)PrepareConstrainedRegions
編譯器使用此方法來(lái)將 catch、finally 和 fault 塊標(biāo)記為受約束的執(zhí)行區(qū)域 (CER)。 標(biāo)記為受約束的區(qū)域的代碼必須只調(diào)用其他具有高可靠性協(xié)定的代碼。 它不能分配或虛調(diào)用未準(zhǔn)備的或不可靠的方法,除非它已準(zhǔn)備好處理失敗。

請(qǐng)注意,除了 NOP 之外,在對(duì) PrepareConstrainedRegions 方法的調(diào)用和 try 塊之間不允許使用其他任何中間語(yǔ)言操作碼。

受約束的執(zhí)行區(qū)域 (CER) 是創(chuàng)作可靠托管代碼的機(jī)制的一部分。CER 定義一個(gè)區(qū)域,在該區(qū)域中公共語(yǔ)言運(yùn)行庫(kù) (CLR) 會(huì)受到約束,不能引發(fā)可使區(qū)域中的代碼無(wú)法完全執(zhí)行的帶外異常。在該區(qū)域中,用戶代碼受到約束,不能執(zhí)行會(huì)導(dǎo)致引發(fā)帶外異常的代碼。PrepareConstrainedRegions 方法必須直接位于 try 塊之前,并將 catch、finally 和 fault 塊標(biāo)記為受約束的執(zhí)行區(qū)域。標(biāo)記為受約束的區(qū)域后,代碼只能調(diào)用其他具有強(qiáng)可靠性約定的代碼,而且代碼不應(yīng)分配或者對(duì)未準(zhǔn)備好的或不可靠的方法進(jìn)行虛調(diào)用,除非代碼已經(jīng)準(zhǔn)備好處理錯(cuò)誤。CLR 為 CER 中正在執(zhí)行的代碼延遲線程中止。

除批注的 try 塊外,受約束的執(zhí)行區(qū)域還以其他形式用于 CLR 中

CLR 會(huì)事先準(zhǔn)備 CER 以避免出現(xiàn)內(nèi)存不足的情況。進(jìn)行事先準(zhǔn)備的目的是為了避免 CLR 在實(shí)時(shí)編譯或類型加載時(shí)發(fā)生內(nèi)存不足的情況。

CER 中不允許下面的操作:

顯式分配。

獲取鎖。

裝箱。

多維數(shù)組訪問(wèn)。

通過(guò)反射進(jìn)行的方法調(diào)用。

Enter 或 Lock。

安全檢查。不執(zhí)行命令,僅鏈接命令。

COM 對(duì)象和代理的 Isinst 和 Castclass

獲取或設(shè)置透明代理上的字段。

序列化。

函數(shù)指針和委托。

如果您計(jì)劃使用適當(dāng)數(shù)量的堆棧空間,則使用 try/finally 或 try/catch 塊后跟對(duì) RuntimeHelpers.PrepareConstrainedRegions 方法的調(diào)用。 如果您正在調(diào)用遞歸方法或計(jì)劃使用大量堆棧空間,則必須使用 RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup 方法。

可如下構(gòu)造代碼
RuntimeHelpers.PrepareConstrainedRegions()
Try
分配大量堆棧空間的代碼
Finally
分配失敗后的清理工作或安全分配空間的代碼

End Try

下面是msdn中可靠地設(shè)置句柄的操作:

要可靠地將句柄設(shè)置為指定的預(yù)先存在的句柄,必須確保本機(jī)句柄的分配,以及該句柄在SafeHandle 對(duì)象中的后續(xù)記錄是原子操作這些操作之間,如果出現(xiàn)任何故障(如線程中止或內(nèi)存不足異常)都會(huì)導(dǎo)致該本機(jī)句柄泄漏。可以使用 PrepareConstrainedRegions 方法確保句柄不會(huì)泄漏。

<StructLayout(LayoutKind.Sequential)> _ Structure MyStructPublic m_outputHandle As IntPtr End Structure 'MyStructNotInheritable Class MySafeHandleInherits SafeHandle' Called by P/Invoke when returning SafeHandlesPublic Sub New()MyBase.New(IntPtr.Zero, True)End SubPublic Function AllocateHandle() As MySafeHandle' Allocate SafeHandle first to avoid failure later.Dim sh As New MySafeHandle()RuntimeHelpers.PrepareConstrainedRegions()TryFinallyDim myStruct As New MyStruct()NativeAllocateHandle(myStruct)sh.SetHandle(myStruct.m_outputHandle)End TryReturn shEnd Function

2)ProbeForSufficientStack

探測(cè)某個(gè)數(shù)量的堆棧空間,以確保不會(huì)在后續(xù)的代碼塊內(nèi)發(fā)生堆棧溢出(假設(shè)您的代碼僅使用有限適中(12頁(yè)棧內(nèi)存)的堆棧空間)。 建議使用受約束的執(zhí)行區(qū)域 (CER),而不使用此方法。

使用方式是

RuntimeHelpers.ProbeForSufficientStack()

分配或使用棧內(nèi)存的語(yǔ)句

3)此外

RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup 也很重要

Public Shared Sub ExecuteCodeWithGuaranteedCleanup ( _
code As RuntimeHelpers…::…TryCode, _ backoutCode As RuntimeHelpers…::…CleanupCode, _ userData AsObject _
)

從其參數(shù)就可以看出它對(duì)處理?xiàng)R绯龅闹匾粤?/p>

code
類型:System.Runtime.CompilerServices.RuntimeHelpers.TryCode
要嘗試的代碼的委托。

backoutCode
類型:System.Runtime.CompilerServices.RuntimeHelpers.CleanupCode
在發(fā)生異常時(shí)要運(yùn)行的代碼的委托。

userData
類型:System.Object
要傳遞給 code 和 backoutCode 的數(shù)據(jù)

總結(jié)

以上是生活随笔為你收集整理的vb.net2019-多线程并行计算(4)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。