浅谈易语言多线程 by逆风
一、簡介
1、線程句柄與線程:
①、關(guān)閉線程句柄對線程的運行不會有影響,關(guān)閉句柄并不代表結(jié)束線程;
②、線程句柄是用于對線程掛起、恢復(fù)、結(jié)束等操作,線程創(chuàng)建后,都會有一個線程句柄,如果不需要對線程句柄進行操作,建議立即關(guān)閉線程句柄;
③、線程句柄必須在適當(dāng)?shù)臅r候關(guān)閉,否則會造成句柄泄露,但不同于內(nèi)存泄露。
2、死鎖、循環(huán)死鎖、活鎖
①、死鎖:線程A占有資源A,線程B占有資源B,線程A申請占有資源B,同時要求占有資源B之后才釋放資源A,而線程B申請占有資源A,同時要求占有資源A之后才釋放資源B,這樣兩個線程互相永久等待對方釋放資源,這就是死鎖。
②、循環(huán)死鎖:線程A占有資源A,線程B占有資源B,線程C占有資源C,線程A申請占有資源B,同時要求占有資源B之后才釋放資源A,而線程B申請占有資源C,同時要求占有資源C之后才釋放資源B,線程C申請占有資源A,同時要求占有資源A之后才釋放資源C,這樣線程互相永久等待對方釋放資源,這就是循環(huán)死鎖。
③、活鎖:提交任務(wù)之后,任務(wù)永遠處于等處理狀態(tài),這就是活鎖。這種情況比較少見,但是出現(xiàn)這種情況,將比死鎖更加不易查覺,避免活鎖的簡單方法是采用先來先處理。
二、注意事項
1、雖然啟動線程要比啟動進程要快,但是啟動線程仍是比較耗時的,因此,不要頻繁的啟動、退出線程,而是啟動線程后將各種任務(wù)處理完成后才退出(這種和線程池差不多);
2、對窗口各種組件操作,最好是在創(chuàng)建該窗口的線程上進行操作,如果在其它線程上操作,可能會引起程序出錯等情況(該錯誤是隨機出現(xiàn)的)。(未找到直接又安全的調(diào)用其他線程創(chuàng)建的組件的方法,有知道的人,麻煩告訴一下,謝謝!)
3、線程運行次序并不是按照我們創(chuàng)建他們時的順序來運行的,CPU處理線程的順序也是不確定的。
4、讀/寫共享資源時一般需要使用許可區(qū),當(dāng)然,在明知讀/寫共享資源不會出現(xiàn)錯誤時,就不需要許可區(qū),這樣可提高性能。
5、在編寫多線程時,必須以多線程的方式考慮讀/寫共享資源,以避免出錯,不然的話,可能會出現(xiàn)各種問題,如:意外退出、在單核CPU上可以穩(wěn)定運行的多線程程序一到多核CPU上運行就出錯。
6、線程中如果需要使用COM對象時,要需將COM對象初始化。
7、結(jié)束線程時,應(yīng)該使用正常的控制代碼使線程退出,強烈反對使用強制結(jié)束線程(),該命令極可能造成一些資源未釋放,從而導(dǎo)致程序的不穩(wěn)定。
8、線程不能頻繁的發(fā)消息給窗口,頻繁的發(fā)消息給窗口,可能會造成窗口響應(yīng)其他事件的緩慢,也是就讓人感覺程序運行很慢;
9、要注意避免各種死鎖、活鎖發(fā)生,確實無法避免的話,就只能想法解鎖,同時得注意解鎖時引發(fā)的新的問題。
三、多線程的誤區(qū)
1、使用處理事件()。非窗口的線程是沒有窗口消息循環(huán),而處理事件()命令是用于消息循環(huán),因此在非窗口的線程上是不必加入“處理事件()”命令;
2、線程越多越好。線程并非越多越好,有些人將單線程改成多線程后,發(fā)現(xiàn)程序能處理更多的任務(wù)了,實際上這種方法是建立別的程序的痛苦之上(當(dāng)然系統(tǒng)有空閑資源就并當(dāng)別論了),別的程序可能因此而變慢。并且,線程數(shù)過多,會使CPU在線程間切換的開銷增加,因而使速度變慢,降低系統(tǒng)性能。在一些阻塞式、耗資源少的線程上需要適當(dāng)?shù)脑黾泳€程數(shù)量,以免程序無響應(yīng)。
四、許可區(qū)
1、許可區(qū)(一般稱為臨界區(qū)),不論是硬件許可資源,還是軟件許可資源,多個線程必須互斥地對它進行訪問,每個線程中訪問許可資源的那段代碼稱為許可區(qū)。
2、注意事項:
①、如果有若干線程要求進入許可區(qū),一次僅允許一個線程進入;
②、任何時候,處于許可區(qū)內(nèi)的線程不可多于一個。如已有線程進入自己的許可區(qū),則其它所有試圖進入許可區(qū)的線程將被掛起,并一直持續(xù)到進入許可區(qū)的線程退出;
③、進入一個空閑的許可區(qū)時,耗時極少,但是進入一個需等待的許可區(qū)時,耗時相對較長,因此需要避免經(jīng)常出現(xiàn)進入需等待的許可區(qū);
④、創(chuàng)建后許可區(qū),在不再使用時,需要將其刪除;
⑤、在使用許可區(qū)時,應(yīng)盡量減少許可區(qū)內(nèi)代碼,避免使用需長時間處理的代碼,使進入許可區(qū)的線程能盡快退出,以便其它線程能進入許可區(qū);
⑥、避免將整個線程處于許可區(qū)內(nèi),盡管它不會出錯,但是由于后來要求進入許可區(qū)的線程全部會被掛起,也就會出現(xiàn)雖然是多線程,但實際是以單線程方式執(zhí)行;
⑦、訪問相同的許可資源時,必須是以相同的許可區(qū)進入訪問,以不同的許可區(qū)進入訪問將可能會使許可區(qū)變的無意義(我在這個坑里蹲了很久,郁悶啊!)。
3、許可區(qū)缺點
①、無法偵測某個許可區(qū)是否可進入。
五、線程同步
1、臨界區(qū)(CriticalSection)
易語言中稱為許可區(qū),這種速度最快,但只能用于本進程的線程同步;
2、事件(Event)
事件可以跨進程使用,它有兩種狀態(tài)、兩種類型:有信號狀態(tài)和無信號狀態(tài)、手動重置事件和自動重置事件。手動重置事件被設(shè)置為有信號狀態(tài)后,會喚醒所有等待的線程,而且一直保持為有信號狀態(tài),直到程序重新把它設(shè)置為無信號狀態(tài)。自動重置事件被設(shè)置為有信號狀態(tài)后,會喚醒“一個”等待中的線程,然后自動恢復(fù)為無信號狀態(tài)。
3、互斥器(Mutex)
互斥器的功能和臨界區(qū)很相似,互斥器所花費的時間比臨界區(qū)多的多,同時它可以跨進程使用。等待一個被鎖住的互斥器可以設(shè)定超時退出,不會像臨界區(qū)那樣無法得知臨界區(qū)的情況,而一直死等。
4、信號量(Semaphore)
與臨界區(qū)相比,它信號量可以跨進程使用,可以設(shè)定同時進入資源總數(shù)。
六、線程通信
線程通信是一般都是需要配合線程同步來使用:
1、使用全局變量進行通信,推薦使用這種方法,該是最快、最方便的通信方式;
2、使用消息通信(需要有消息隊列才能使用);
3、使用Socket進行通信(可以跨計算機使用);
—一些多線程操作建議—
多線程安全的核心支持庫 http://bbs.eyuyan.com/read.php?tid=316079
一定要用沒有問題的核心支持庫。。注意,是核心支持庫,不是多線程支持庫,原來那個有問題即使不操作全局變量一樣會出問題
多少人是百度搜索下載個破解版易語言一直用個有bug的支持庫。。
我相信很多人的問題都是提示XXXXX內(nèi)存訪問錯誤.
我們就了解一下這個錯誤怎么產(chǎn)生
線程a對變量操作的時候b也操作,a改寫了文本申請了新的內(nèi)存地址同時修改了指針然后釋放了原指針,但是b讀取了原指針需要讀取數(shù)據(jù)的時候,a已經(jīng)把指針釋放了.然后就各種內(nèi)存錯誤。。
值得注意的是,一邊讀一邊執(zhí)行寫操作也不行,
你線程a對全局文本變量賦值"1234567",那么在線程b對全局變量讀寫前,會經(jīng)過至少兩個步驟
1、獲取內(nèi)存區(qū)域大小,假設(shè)是8的話
2、讀取內(nèi)容 而實際上進行到讀取第8位的時候,你線程a重新給全局文本變量賦值“123456”,這就導(dǎo)致“踏空”,于是程序直接崩潰。而對于長度固定的變量進行讀寫時,就算讀取到的數(shù)據(jù)是錯誤的,也不至于崩潰(當(dāng)然,這不是說寫程序可以不嚴謹,寧愿讀錯也不加保護,當(dāng)你的程序足夠大的時候,一點點小小的問題都會導(dǎo)致致命錯誤)
關(guān)于只讀不寫操作。。我認為不需要加許可證。。也有大神說要加。這個不清楚。。
另外盡量用整數(shù)型變量。。下面會講解
http://blog.csdn.net/q349980363/article/details/8012495
上面那個是某大神列出的易語言數(shù)據(jù)類型內(nèi)存分布格式
里面幾個沒必要說明的可以進行多線程讀寫操作,其他以外的都有可能引發(fā)問題
關(guān)于易語言控件操作問題。。
控件操作一定要加許可證。。這個大家都知道。。
但這樣依然會不那么穩(wěn)定。。
我建議調(diào)用標簽反饋事件。。雖然比較卡
不過我的遺忘是先獲取控件句柄,然后用api和發(fā)送信息在線程里面操作,線程里面發(fā)送信息應(yīng)該用SendMessage()、PostMessage()
我個人認為這樣再加上許可證。。算是比較穩(wěn)定
關(guān)于易語言啟動線程,結(jié)束線程問題
啟動我建議用官方的多線程支持庫。。雖然最終都是調(diào)用CreateThread..
結(jié)束線程我強烈反對強制結(jié)束線程,無論是什么支持庫,什么多線程模塊,都是調(diào)用TerminateThread,應(yīng)該盡量避免這樣結(jié)束線程,我認為應(yīng)該在線程內(nèi)退出
順便提一下。。不知道是不是風(fēng)列的原因。。很多人都喜歡用多線程支持庫1.1,里面有個退出線程命令我反對,因為這個命令是調(diào)用ExitThread,該函數(shù)將終止線程的運行,并導(dǎo)致操作系統(tǒng)清除該線程使用的所有操作系統(tǒng)資源。但是有一些資源將不被撤消。由于這個原因,最好從線程函數(shù)返回,而不是通過調(diào)用ExitThread 來返回。
關(guān)于句柄問題,不需要一定要CloseHandle,防止句柄泄露,不過我一般創(chuàng)建線程都不提供句柄參數(shù),讓系統(tǒng)自動銷毀
因為我很少用到TerminateThread,當(dāng)然寫發(fā)帖器這些需要驗證碼操作就不可避免用到句柄。。為了方便。。多少機器跟了風(fēng)列的思路。。SuspendThread線程,輸入驗證碼又ResumeThread..
這里講解下原子操作
.版本 2 .支持庫 spec .程序集 程序集1 .程序集變量 sum, 整數(shù)型 .程序集變量 locked, _原子鎖類 .子程序 _啟動子程序, 整數(shù)型, , 本子程序在程序啟動后最先執(zhí)行 .局部變量 i, 整數(shù)型 .局部變量 idz, 整數(shù)型, , "0" .局部變量 time, 整數(shù)型 ' 轉(zhuǎn)換類et調(diào)試 () 重定義數(shù)組 (idz, 假, 10) time = 取啟動時間 () .計次循環(huán)首 (10, i)Thread.啟動 (&累加, , idz [i]) .計次循環(huán)尾 () .計次循環(huán)首 (10, i)Thread.等待 (idz [i]) .計次循環(huán)尾 () 調(diào)試輸出 (取啟動時間 () - time, sum) 返回 (0) ' 可以根據(jù)您的需要返回任意數(shù)值 .子程序 累加 .局部變量 i .變量循環(huán)首 (1, 9999999, 1, i) .變量循環(huán)尾 () locked.加減 (sum, i)這也是我為什么提倡大家盡量用整數(shù)型變量原因了
整數(shù)型變量是固定長度,而且可以加原子鎖,速度遠快過許可證,不信自己測試
最后是一些細節(jié)問題.. 多線程寫法各種各樣,我比較推薦飛龍那種 當(dāng)然無論你怎么寫,都應(yīng)該盡量避免操作全局變量和控件 這里提一下 很多人看到多線程出現(xiàn)內(nèi)存錯誤 就想辦法去優(yōu)化內(nèi)存 使用各種內(nèi)存優(yōu)化等等。。爆吧界應(yīng)該不少人這樣 所謂的內(nèi)存優(yōu)化模塊應(yīng)該都是調(diào)用SetProcessWorkingSetSize, 這個命令就是將程序所使用的物理內(nèi)存盡量地向虛擬內(nèi)存中壓 表面上看,物理內(nèi)存占用確實是少了. 但是,一旦程序需要使用到已經(jīng)被強行壓到虛擬內(nèi)存(也就是硬盤頁面文件)中的內(nèi)容時,又得重新從虛擬內(nèi)存里讀出來. 目前最好的硬盤速度比起內(nèi)存來說那都至少是慢了幾十上百倍,于是此招就會造成當(dāng)前程序的運行效率嚴重下降,同時因為頻繁讀硬盤,占用了本來就不多的帶寬,搞得整個系統(tǒng)的運行效率都下降了. 我覺得這個命令應(yīng)該在程序空閑時使用。。切忌不要頻繁調(diào)用 爆吧界很多機器都是從一開始就優(yōu)化,隔幾秒優(yōu)化一次到結(jié)束。。是利是弊最終還是取決于你的程序 我個人反對調(diào)用模塊,因為你不知道模塊里面有什么問題 這里提下我遺忘在xp系統(tǒng)崩潰問題 因為百度坑爹的驗證碼在圖片框無法顯示,所以需要轉(zhuǎn)換圖片 然后我用了精易模塊那個圖片轉(zhuǎn)換命令,但這個命令在xp系統(tǒng)是比較容易崩潰 但我技術(shù)有限,目前無法解決
關(guān)于易語言雙核親和性問題
SetProcessAffinityMask這個命令是把程序綁定在一個核上。。。我個人感覺沒什么用,而且失去了多核的優(yōu)勢
提到SetProcessAffinityMask就不得不提到 SetThreadIdealProcessor
SetProcessAffinityMask是自動切換線程到同核內(nèi)執(zhí)行,后者是切換到其他空閑執(zhí)行這就是區(qū)別,主要區(qū)別是充分利用所有多核CPU
最后是一些細節(jié)問題.. 多線程寫法各種各樣,我比較推薦飛龍那種 當(dāng)然無論你怎么寫,都應(yīng)該盡量避免操作全局變量和控件 這里提一下 很多人看到多線程出現(xiàn)內(nèi)存錯誤 就想辦法去優(yōu)化內(nèi)存 使用各種內(nèi)存優(yōu)化等等。。爆吧界應(yīng)該不少人這樣 所謂的內(nèi)存優(yōu)化模塊應(yīng)該都是調(diào)用SetProcessWorkingSetSize, 這個命令就是將程序所使用的物理內(nèi)存盡量地向虛擬內(nèi)存中壓 表面上看,物理內(nèi)存占用確實是少了. 但是,一旦程序需要使用到已經(jīng)被強行壓到虛擬內(nèi)存(也就是硬盤頁面文件)中的內(nèi)容時,又得重新從虛擬內(nèi)存里讀出來. 目前最好的硬盤速度比起內(nèi)存來說那都至少是慢了幾十上百倍,于是此招就會造成當(dāng)前程序的運行效率嚴重下降,同時因為頻繁讀硬盤,占用了本來就不多的帶寬,搞得整個系統(tǒng)的運行效率都下降了. 我覺得這個命令應(yīng)該在程序空閑時使用。。切忌不要頻繁調(diào)用 爆吧界很多機器都是從一開始就優(yōu)化,隔幾秒優(yōu)化一次到結(jié)束。。是利是弊最終還是取決于你的程序 我個人反對調(diào)用模塊,因為你不知道模塊里面有什么問題 這里提下我遺忘在xp系統(tǒng)崩潰問題 因為百度坑爹的驗證碼在圖片框無法顯示,所以需要轉(zhuǎn)換圖片 然后我用了精易模塊那個圖片轉(zhuǎn)換命令,但這個命令在xp系統(tǒng)是比較容易崩潰 但我技術(shù)有限,目前無法解決
很多軟件都喜歡在程序啟動后使用一個線程不斷保存信息,這個我強烈反對
不談操作控件的問題
易語言本身的分割文本命令、讀寫配置項()命令、取現(xiàn)行時間()
這些命令在多線程會出問題
那些輸出用取現(xiàn)行時間的還是改為用api吧。。
另外有些編碼轉(zhuǎn)換模塊會出問題。。具體百度
我相信很多機器都用到延遲這個命令
在多線程中我不建議用這個
我建議用延時
“延遲”,在執(zhí)行時允許用戶執(zhí)行其它的操作(如:單擊按鈕等);
“延時”,在執(zhí)行時程序會進入“假死“狀態(tài),用戶的其他操作程序?qū)o法響應(yīng),必須等到語句執(zhí)行結(jié)束才能恢復(fù)。
據(jù)我測試,延時在多線程中也可以操作控件
或者大家可以用什么高精度延時也行
關(guān)于使用控件屬性問題,我個人不喜歡
不論是否穩(wěn)定,但可以使用變量的速度肯定快過使用控件屬性
我的遺忘是啟動后直接給變量賦值
大家的變量是啟動后賦值還是任務(wù)前賦值還是取決于你的軟件怎么寫~
下面介紹易語言的多線程編程方法。
?通過研究易語言附帶的兩個多線程例程,總結(jié)如下:
?(一)、先看易語言對自己的多程機制的解釋:
?1、創(chuàng)建進入許可證:創(chuàng)建并返回一個進入許可證數(shù)值,此許可證值用作進入程序中的指定許可代碼區(qū),以避免多線程沖突。
?2、刪除進入許可證:刪除由“創(chuàng)建進入許可證”命令所創(chuàng)建返回的進入許可證,以釋放系統(tǒng)資源。
?3、啟動線程:創(chuàng)建并啟動一條線程,可重復(fù)使用以創(chuàng)建多條線程。
?4、進入許可區(qū):根據(jù)已經(jīng)創(chuàng)建的許可證進入指定許可代碼區(qū),在此線程未退出之前,其它線程如要通過同一個進入許可證進入該許可代碼區(qū)則必須先等待此線程退出許可代碼區(qū),從而保證了指定許可代碼區(qū)在任何時候都只能有一條線程進入并執(zhí)行。
?5、退出許可區(qū):指示當(dāng)前線程將退出許可代碼區(qū),并允許其它使用同一進入許可證的線程進入此許可代碼區(qū)。
?(二)、易語言的多線程編程過程大約如下:
?1、先用“創(chuàng)建進入許可證”命令為一個線程進入一個指定的許可代碼區(qū)建立一個許可證。
?2、用“啟動線程”命令創(chuàng)建并啟動一條線程,以運行一個線程的子程序。
?3、在一個線程子程序里用“進入許可區(qū)”使該線程占用一個許可代碼區(qū),并鎖定該代碼區(qū)不讓其他線程進入,并鎖定其他線程運行,以避免線程沖突。
?4、使用“退出許可區(qū)”解鎖該許可代碼區(qū),以便讓其他線程進入。若想使多個線程同時運行,我們可以為每個線程建立一個進入許可證,進入許可區(qū)與退出許可區(qū)連著進行使多個線程同步運行。
?5、當(dāng)退出程序時,要刪除進入許可證以釋放系統(tǒng)資源。
總結(jié)
以上是生活随笔為你收集整理的浅谈易语言多线程 by逆风的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 先进驾驶员辅助系统中用于车辆检测的雷达和
- 下一篇: 微信、支付宝二码合一扫码支付实现思路