新聞中心
多線程調(diào)試 linux:技巧大全

網(wǎng)站設(shè)計(jì)制作過(guò)程拒絕使用模板建站;使用PHP+MYSQL原生開(kāi)發(fā)可交付網(wǎng)站源代碼;符合網(wǎng)站優(yōu)化排名的后臺(tái)管理系統(tǒng);網(wǎng)站建設(shè)、網(wǎng)站制作收費(fèi)合理;免費(fèi)進(jìn)行網(wǎng)站備案等企業(yè)網(wǎng)站建設(shè)一條龍服務(wù).我們是一家持續(xù)穩(wěn)定運(yùn)營(yíng)了十年的創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司。
在軟件開(kāi)發(fā)中,多線程編程已經(jīng)成為了非常普遍的技術(shù)。然而,多線程編程也帶來(lái)了許多調(diào)試難題,因?yàn)槎鄠€(gè)線程之間的交互以及競(jìng)爭(zhēng)會(huì)導(dǎo)致程序出現(xiàn)意料之外的結(jié)果。為了解決這些問(wèn)題,你需要掌握一些多線程調(diào)試的技巧。
本文將為你介紹一些常見(jiàn)的多線程調(diào)試技巧,來(lái)幫助你定位和解決多線程編程中的問(wèn)題。
1. 使用調(diào)試器
使用調(diào)試器來(lái)調(diào)試多線程程序是最常見(jiàn)的方法。調(diào)試器可以讓你檢查程序中的每個(gè)線程,包括它們的堆棧、變量、程序計(jì)數(shù)器等。你可以在需要的時(shí)候停止或繼續(xù)任何一個(gè)或多個(gè)線程,并檢查它們?cè)诓煌瑫r(shí)刻的狀態(tài)。
在 Linux 中,你可以使用 GDB 或 CLion 等調(diào)試器來(lái)進(jìn)行多線程調(diào)試。下面是一些使用 GDB 調(diào)試多線程程序的技巧:
– 使用 command 命令創(chuàng)建自定義命令。你可以使用 GDB 的 command 命令來(lái)創(chuàng)建自定義命令,這些命令可以用來(lái)檢查線程之間的狀態(tài)、設(shè)置斷點(diǎn)等操作。
– 設(shè)置斷點(diǎn)。在多線程程序中,你需要在正確的時(shí)機(jī)設(shè)置斷點(diǎn),并檢查每個(gè)線程在達(dá)到斷點(diǎn)時(shí)的狀態(tài)。
– 使用線程列表命令。GDB 的 info threads 命令可以列出所有正在運(yùn)行的線程,你可以使用該命令來(lái)檢查每個(gè)線程的狀態(tài)和堆棧信息。
2. 使用 log
如果你的程序中存在未捕獲的異常或信號(hào),你可以在程序中記錄日志以便后續(xù)分析。在多線程編程中,使用 log 來(lái)記錄每個(gè)線程的狀態(tài)和行為是非常有用的。你可以使用 log 來(lái)記錄以下信息:
– 隊(duì)列和緩沖區(qū)的狀態(tài)
– 每個(gè)線程的輸入和輸出
– 每個(gè)線程的堆棧
你可以使用 syslog 或者其他日志框架來(lái)記錄日志。如果你想對(duì)每個(gè)線程單獨(dú)記錄日志,你可以使用線程特定的標(biāo)識(shí)符來(lái)記錄日志。
3. 使用靜態(tài)分析工具
靜態(tài)分析工具可以幫助你找到程序中的潛在錯(cuò)誤。在多線程程序中,你可以使用靜態(tài)分析工具來(lái)找到以下問(wèn)題:
– 數(shù)據(jù)競(jìng)爭(zhēng):多個(gè)線程同時(shí)訪問(wèn)共享資源,導(dǎo)致寫(xiě)入沖突
– 死鎖:多個(gè)線程同時(shí)等待同一個(gè)鎖,導(dǎo)致無(wú)法繼續(xù)執(zhí)行
– 值域錯(cuò)誤:變量的值不在其有效范圍內(nèi),可能導(dǎo)致內(nèi)存錯(cuò)誤或者安全問(wèn)題
在 Linux 中,你可以使用 Clang 或者 Valgrind 等靜態(tài)分析工具來(lái)進(jìn)行多線程程序分析。
4. 使用多線程可視化工具
多線程可視化工具可以幫助你更好地理解程序的執(zhí)行流程。這些工具通常會(huì)將每個(gè)線程表示為一個(gè)顏色編碼的線條或者圖標(biāo),并提供一個(gè)時(shí)間軸來(lái)顯示每個(gè)線程的執(zhí)行時(shí)間以及線程之間的交互。
在 Linux 中,你可以使用 PARSEC 或者 Camcops 等多線程可視化工具來(lái)進(jìn)行多線程程序分析。
5. 編寫(xiě)可重現(xiàn)的測(cè)試用例
在找出多線程程序中的問(wèn)題時(shí),編寫(xiě)可重現(xiàn)的測(cè)試用例是非常重要的。一個(gè)可重現(xiàn)的測(cè)試用例可以讓你輕松地重現(xiàn)程序中的問(wèn)題,并找到導(dǎo)致程序異常的原因。
在編寫(xiě)測(cè)試用例時(shí),你需要注意以下幾點(diǎn):
– 在程序中使用固定的隨機(jī)種子以確保測(cè)試的可重現(xiàn)性
– 嘗試模擬不同的并況,包括競(jìng)爭(zhēng)和互斥訪問(wèn)
– 檢查每個(gè)線程的狀態(tài),并確保線程之間的互斥訪問(wèn)正確實(shí)現(xiàn)
結(jié)論
在多線程編程中,調(diào)試是一個(gè)非常復(fù)雜的過(guò)程,需要你掌握大量的技巧。本文介紹了一些常見(jiàn)的多線程調(diào)試技巧,包括使用調(diào)試器、使用 log、使用靜態(tài)分析工具、使用多線程可視化工具以及編寫(xiě)可重現(xiàn)的測(cè)試用例。
使用這些技巧可以幫助你定位和解決程序中的問(wèn)題,提高程序的穩(wěn)定性和可靠性。同時(shí),也可以增加你在多線程編程方面的經(jīng)驗(yàn)和技能。
相關(guān)問(wèn)題拓展閱讀:
- 【求助】linux下的C語(yǔ)言多線程,怎樣監(jiān)視鍵盤(pán)上的輸入?
- linux內(nèi)核如何打開(kāi)超線程
- linux手冊(cè)翻譯——pthread_setname_np()
【求助】linux下的C語(yǔ)言多線程,怎樣監(jiān)視鍵盤(pán)上的輸入?
發(fā)所用語(yǔ)言為C..
一般的..要想學(xué)好嵌入式開(kāi)發(fā)..就要兩個(gè)都會(huì)..
如果只學(xué)linux,這個(gè)只是為以后從事linux服務(wù)器搭建,管理和維護(hù)等..差不多就是跟硬件打交道..
而嵌入式開(kāi)發(fā)就相當(dāng)于..在windows下用C,C++,C#,java等開(kāi)發(fā)一樣..只不過(guò)他的開(kāi)發(fā)平臺(tái)換成了linux…
如果想自學(xué)建議按照以下步驟:
學(xué)習(xí)步驟如下:
1、Linux 基礎(chǔ)
安裝Linux操作系統(tǒng)
Linux文件系統(tǒng)
Linux常用命令
Linux啟動(dòng)過(guò)程詳解
熟悉Linux服務(wù)能夠獨(dú)立安裝Linux操作系培悔陪統(tǒng)
能夠熟練使用Linux系統(tǒng)的基本命令
認(rèn)識(shí)Linux系統(tǒng)的常用服務(wù)安裝Linux操作系統(tǒng)
Linux基本命令實(shí)踐
設(shè)置Linux環(huán)境變量
定制Linux的服務(wù) Shell 編程基礎(chǔ)使用vi編輯文件
使用Emacs編輯文件
使用其他編輯器
2、Shell 編程基礎(chǔ)
Shell簡(jiǎn)介
認(rèn)識(shí)后臺(tái)程序
Bash編程熟悉Linux系統(tǒng)下的編輯環(huán)境
熟悉Linux下的各種Shell
熟練進(jìn)行shell編程熟悉vi基本操作
熟悉Emacs的基本操作
比較不同shell的區(qū)別
編寫(xiě)一個(gè)測(cè)試服務(wù)器是否連通的shell腳本程序
編寫(xiě)一個(gè)查看進(jìn)程是否存在的shell腳本程序
編寫(xiě)一個(gè)帶有循環(huán)語(yǔ)句的shell腳本程序
3、Linux 下的 C 編程基礎(chǔ)
linux C語(yǔ)言環(huán)境概述
Gcc使用方法
Gdb調(diào)試技術(shù)
Autoconf
Automake
Makefile
代碼優(yōu)化 熟悉Linux系統(tǒng)下的開(kāi)發(fā)環(huán)境
熟悉Gcc編譯器
熟悉Makefile規(guī)則編寫(xiě)Hello,World程序
使用 make命令編譯程序
編寫(xiě)帶有一個(gè)循環(huán)的程序
調(diào)試一個(gè)有問(wèn)題的程序
4、嵌入式系統(tǒng)開(kāi)發(fā)基礎(chǔ)
嵌入式系統(tǒng)概述
交叉編譯
配置TFTP服務(wù)
配置NFS服務(wù)
下載Bootloader和內(nèi)核
嵌入式Linux應(yīng)用軟件開(kāi)發(fā)流程
熟悉嵌入式系統(tǒng)概念以及開(kāi)發(fā)流程
建立嵌入式系統(tǒng)開(kāi)發(fā)環(huán)境制作cross_gcc工具鏈
編譯并下載U-boot
編譯并下載Linux內(nèi)核
編譯并下載Linux應(yīng)用程序
嵌入式系統(tǒng)移植
Linux內(nèi)核代碼
平配蠢臺(tái)相關(guān)代碼分析
ARM平臺(tái)介紹
平臺(tái)移植的關(guān)鍵技術(shù)
移植Linux內(nèi)核到 ARM平臺(tái) 了解移植的概念
能夠移植Linux內(nèi)核移植Linux2.6內(nèi)核到 ARM9開(kāi)發(fā)板
5、嵌入式 Linux 下串口通信
串行I/O的基本概念
嵌入式Linux應(yīng)用軟件開(kāi)發(fā)流程
Linux系統(tǒng)的文件和設(shè)備
與文件相關(guān)的系統(tǒng)調(diào)用
配置超級(jí)終端和MiniCOM 能夠熟悉進(jìn)行串口通信
熟悉文件I/O 編寫(xiě)串口通信程序
編寫(xiě)多串口通信程序
6、嵌入式系統(tǒng)中多進(jìn)程程序設(shè)計(jì)
Linux系統(tǒng)進(jìn)程概述
嵌入式系統(tǒng)的進(jìn)程特點(diǎn)
進(jìn)程操作
守護(hù)進(jìn)程
相關(guān)的系統(tǒng)調(diào)用了解Linux系統(tǒng)中進(jìn)程的概念
能夠編寫(xiě)多進(jìn)程程序編寫(xiě)多進(jìn)程程序
編寫(xiě)一個(gè)守護(hù)進(jìn)程程序
sleep系統(tǒng)調(diào)用任務(wù)管理、同步與通信 Linux任務(wù)概述
任務(wù)調(diào)度
管道
信號(hào)
共享內(nèi)存
任務(wù)管理 API 了解Linux系統(tǒng)任務(wù)管理機(jī)制
熟悉進(jìn)程間通信的幾種方式
熟悉嵌入式Linux中的任務(wù)間同步與通信
編寫(xiě)一個(gè)簡(jiǎn)單的管道程序?qū)崿F(xiàn)文件傳輸
編寫(xiě)前薯一個(gè)使用共享內(nèi)存的程序
7、嵌入式系統(tǒng)中多線程程序設(shè)計(jì)
線程的基礎(chǔ)知識(shí)
多線程編程方法
線程應(yīng)用中的同步問(wèn)題了解線程的概念
能夠編寫(xiě)簡(jiǎn)單的多線程程序編寫(xiě)一個(gè)多線程程序
8、嵌入式 Linux 網(wǎng)絡(luò)編程
網(wǎng)絡(luò)基礎(chǔ)知識(shí)
嵌入式Linux中TCP/IP網(wǎng)絡(luò)結(jié)構(gòu)
socket 編程
常用 API函數(shù)
分析Ping命令的實(shí)現(xiàn)
基本UDP套接口編程
許可證管理
PPP協(xié)議
GPRS 了解嵌入式Linux網(wǎng)絡(luò)體系結(jié)構(gòu)
能夠進(jìn)行嵌入式Linux環(huán)境下的socket 編程
熟悉UDP協(xié)議、PPP協(xié)議
熟悉GPRS 使用socket 編寫(xiě)代理服務(wù)器
使用socket 編寫(xiě)路由器
編寫(xiě)許可證服務(wù)器
指出TCP和UDP的優(yōu)缺點(diǎn)
編寫(xiě)一個(gè)web服務(wù)器
編寫(xiě)一個(gè)運(yùn)行在 ARM平臺(tái)的網(wǎng)絡(luò)播放器
9、GUI 程序開(kāi)發(fā)
GUI基礎(chǔ)
嵌入式系統(tǒng)GUI類型
編譯QT
進(jìn)行QT開(kāi)發(fā)熟悉嵌入式系統(tǒng)常用的GUI
能夠進(jìn)行QT編程使用QT編寫(xiě)“Hello,World”程序
調(diào)試一個(gè)加入信號(hào)/槽的實(shí)例
通過(guò)重載QWidget 類方法處理事件
10、Linux 字符設(shè)備驅(qū)動(dòng)程序
設(shè)備驅(qū)動(dòng)程序基礎(chǔ)知識(shí)
Linux系統(tǒng)的模塊
字符設(shè)備驅(qū)動(dòng)分析
fs_operation結(jié)構(gòu)
加載驅(qū)動(dòng)程序了解設(shè)備驅(qū)動(dòng)程序的概念
了解Linux字符設(shè)備驅(qū)動(dòng)程序結(jié)構(gòu)
能夠編寫(xiě)字符設(shè)備驅(qū)動(dòng)程序編寫(xiě)Skull驅(qū)動(dòng)
編寫(xiě)鍵盤(pán)驅(qū)動(dòng)
編寫(xiě)I/O驅(qū)動(dòng)
分析一個(gè)看門(mén)狗驅(qū)動(dòng)程序
對(duì)比Linux2.6內(nèi)核與2.4內(nèi)核中字符設(shè)備驅(qū)動(dòng)的不同
Linux 塊設(shè)備驅(qū)動(dòng)程序塊設(shè)備驅(qū)動(dòng)程序工作原理
典型的塊設(shè)備驅(qū)動(dòng)程序分析
塊設(shè)備的讀寫(xiě)請(qǐng)求隊(duì)列了解Linux塊設(shè)備驅(qū)動(dòng)程序結(jié)構(gòu)
能夠編寫(xiě)簡(jiǎn)單的塊設(shè)備驅(qū)動(dòng)程序比較字符設(shè)備與塊設(shè)備的異同
編寫(xiě)MMC卡驅(qū)動(dòng)程序
分析一個(gè)文件系統(tǒng)
對(duì)比Linux2.6內(nèi)核與2.4內(nèi)核中塊設(shè)備驅(qū)動(dòng)的不同
11、文件系統(tǒng)
虛擬文件系統(tǒng)
文件系統(tǒng)的建立
ramfs內(nèi)存文件系統(tǒng)
proc文件系統(tǒng)
devfs 文件系統(tǒng)
MTD技術(shù)簡(jiǎn)介
MTD塊設(shè)備初始化
MTD塊設(shè)備的讀寫(xiě)操作了解Linux系統(tǒng)的文件系統(tǒng)
了解嵌入式Linux的文件系統(tǒng)
了解MTD技術(shù)
能夠編寫(xiě)簡(jiǎn)單的文件系統(tǒng)為 ARM9開(kāi)發(fā)板添加 MTD支持
移植JFFS2文件系統(tǒng)
通過(guò)proc文件系統(tǒng)修改操作系統(tǒng)參數(shù)
分析romfs 文件系統(tǒng)源代碼
創(chuàng)建一個(gè)cramfs 文件系統(tǒng)
望采納:可是一個(gè)字一個(gè)字錢(qián)敲出來(lái)的..
另外,站長(zhǎng)團(tuán)上有產(chǎn)品團(tuán)購(gòu),便宜有保證
在襪沖Microsoft Windows 中,鍵盤(pán)和鼠標(biāo)是兩個(gè)標(biāo)準(zhǔn)的用戶輸入源,在一些交疊的操作中通常相互補(bǔ)充使用。當(dāng)然,鼠標(biāo)在今天的應(yīng)用程序中比10年前使用得更為廣泛。甚至在一些應(yīng)用程序中,我們更習(xí)慣于使用鼠標(biāo),例如在游戲、畫(huà)圖程序、音樂(lè)程序,以及Web創(chuàng)覽器等程序中就是這樣。然而,我們可以不使用鼠標(biāo),但絕對(duì)不能從一般的PC中拆掉鍵盤(pán)。
Windows程序獲得鍵盤(pán)輸入的方式:鍵盤(pán)輸入以消息的形式傳遞給程序的窗口過(guò)程。實(shí)際上,之一次學(xué)習(xí)消息時(shí),鍵盤(pán)就是一個(gè)明顯的例子:消息應(yīng)該傳遞給應(yīng)用程序的信息類型。
Windows用8種不同的消息來(lái)傳遞不同的鍵盤(pán)事件。這好像太多了,但是(如野就像我們所看到的一樣)程序可以忽略其中至少一半的消息而不會(huì)有任何問(wèn)題。并且,在大多數(shù)情況下,這些消息中包含的鍵盤(pán)信息會(huì)多于程序所需要的。處理鍵盤(pán)的部分工作就是識(shí)別出哪些消息是重要的,哪些是不重要的。
鍵盤(pán)基礎(chǔ)知識(shí)
雖然應(yīng)用程序在很多情況下可以通過(guò)鼠標(biāo)實(shí)現(xiàn)信息的輸入,但到現(xiàn)在為止鍵盤(pán)仍然是PC機(jī)中不可替代的重要輸入設(shè)備。
用鍵盤(pán)當(dāng)作輸入設(shè)備,每當(dāng)用戶按下或釋放某一個(gè)鍵時(shí),會(huì)產(chǎn)生一個(gè)中斷,該中斷激活鍵盤(pán)驅(qū)動(dòng)程序KEYBOARD.DRV來(lái)對(duì)鍵盤(pán)中斷進(jìn)行處理。 KEYBOARD.DRV程序會(huì)根據(jù)用戶的不同操作進(jìn)行編碼,然后調(diào)用Windows用戶模塊USER.EXE生成鍵盤(pán)消息,并將該消息發(fā)送到消息隊(duì)列中等候處理。
1.掃描碼和虛擬碼
掃描碼對(duì)應(yīng)著鍵盤(pán)上的不同鍵,每一個(gè)鍵被按下或釋放時(shí),都會(huì)產(chǎn)生一個(gè)唯一的掃描碼作為本身的標(biāo)識(shí)。掃描碼依賴于具體的硬告橡殲件設(shè)備,即當(dāng)相同的鍵被按下或釋放時(shí),在不同的機(jī)器上可能產(chǎn)生不同的掃描碼。在程序中通常使用由Windows系統(tǒng)定義的與具體設(shè)備無(wú)關(guān)的虛擬碼。在擊鍵產(chǎn)生掃描碼的同時(shí),鍵盤(pán)驅(qū)動(dòng)程序KEYBOARD.DRV截取鍵的掃描碼,然后將其翻譯成對(duì)應(yīng)的虛擬碼,再將掃描碼和虛擬碼一齊編碼形成鍵盤(pán)消息。所以,最后發(fā)送到消息隊(duì)列的鍵盤(pán)消息中,既包含了掃描碼又包含了虛擬碼。
經(jīng)常使用的虛擬碼在WINDOWS.H文件中定義,常用虛擬碼的數(shù)值、常量符號(hào)和含義如表所示。
取值(16進(jìn)制) 常量符號(hào) 含義
VK_LBUTTON 鼠標(biāo)左鍵
VK_RBUTTON 鼠標(biāo)右鍵
VK_CANCEL Break中斷鍵
VK_MBUTTON 鼠標(biāo)中鍵
未定義
VK_BACK (BackSpace)鍵
VK_TAB Tab鍵
0A-0B — 未定義
0C VK_CLEAR Clear鍵
0D VK_RETURN Enter鍵
0E-0F — 未定義
VK_SHIFT Shift鍵
VK_CONTROL Ctrl鍵
VK_MENU Alt鍵
VK_PAUSE Pause鍵
VK_CAPTIAL CapsLock鍵
漢字系統(tǒng)保留
1A — 未定義
1B VK_ESCAPE Esc鍵
1C-1F — 漢字系統(tǒng)保留
VK_SPACE 空格鍵
VK_PRIOR PageUp鍵
VK_NEXT PageDown鍵
VK_END End鍵
VK_HOME Home鍵
VK_LEFT ←(Left Arrow)鍵
VK_UP ↑(Up Arrow)鍵
VK_RIGHT →(Right Arrow)鍵
VK_DOWN ↓(Down Arrow)鍵
VK_SELECT Select鍵
2A — OEM保留
2B VK_EXECUTE Execute鍵
2C VK_SNAPSHOT Print Screen鍵
2D VK_INSERT Insert鍵
2E VK_DELETE Delete鍵
2F VK_HELP Help鍵
VK_0-VK_9 數(shù)字鍵0-9
3A未定義
A VK_A-VK_Z 字母鍵A-Z
5B-5F — 未定義
VK_NUMPAD0-VK_NUMPAD9 小鍵盤(pán)數(shù)字鍵0-9
6A VK_MULTIP *(乘號(hào))鍵
6B VK_ADD +(加號(hào))鍵
6C VK_SEPAPATOR 分隔符鍵
6E VK_SURACT -(減號(hào))鍵
6F VK_DECIMAL .(小數(shù)點(diǎn))鍵
VK_DIVIDE /(除號(hào))鍵
F VK_F1-VK_F24 F1-F24功能鍵
VK_NUMBERLOCK Number lock鍵
VK_SCROLL Scroll lock鍵
B9 — 未定義
BA-C0 — OEM保留
C1-DA — 未定義
DB_E4 — OEM保留
E5 — 未定義
E6 — OEM保留
E7-E8 — 未定義
E9-F5 — OEM保留
F6-FE — 未定義
2.輸入焦點(diǎn)
同一時(shí)刻,Windows中可能有多個(gè)不同的程序在運(yùn)行,也就是說(shuō)有多個(gè)窗口同時(shí)存在。這時(shí),鍵盤(pán)由多個(gè)窗口共享,但只有一個(gè)窗口能夠接收到鍵盤(pán)消息,這個(gè)能夠接收鍵盤(pán)消息的窗口被稱為擁有輸入焦點(diǎn)的窗口。
擁有輸入焦點(diǎn)的窗口應(yīng)該是當(dāng)前的活動(dòng)窗口,或者是活動(dòng)窗口的子窗口,其標(biāo)題和邊框會(huì)以高亮度顯示,以區(qū)別于其他窗口。擁有輸入焦點(diǎn)的也可以是圖標(biāo)而不是窗口,此時(shí),Windows也將消息發(fā)送給圖標(biāo),只是消息的格式略有不同。
窗口過(guò)程可以通過(guò)發(fā)送WM_SETFOCUS和 WM_KILLFOCUS消息使窗體獲得或失去輸入焦點(diǎn)。程序也可以通過(guò)捕獲WM_SETFOCUS和WM_KILLFOCUS消息來(lái)判斷窗體何時(shí)獲得或失去輸入焦點(diǎn)。其中WM_SETFOCUS消息表示窗口正獲得輸入焦點(diǎn),WM_ KILLFOCUS消息表示窗口正失去輸入焦點(diǎn)。
3.鍵盤(pán)消息
鍵盤(pán)消息分為系統(tǒng)鍵消息和非系統(tǒng)鍵消息。系統(tǒng)鍵消息是指由Aft鍵和其他鍵組合而產(chǎn)生的按鍵消息。當(dāng)系統(tǒng)鍵被按下時(shí)產(chǎn)生WM_ SYSKEYDOWN消息,當(dāng)系統(tǒng)鍵被釋放時(shí)產(chǎn)生WM_SYSKEYUP消息。 Aft鍵與其他鍵形成的組合鍵通常用于對(duì)程序菜單和系統(tǒng)菜單進(jìn)行選擇,或用于在不同的程序之間進(jìn)行切換。因此,系統(tǒng)鍵消息應(yīng)該交由Windows進(jìn)行處理,用戶所編制的程序一般不處理系統(tǒng)鍵消息,而是將這些消息交由DefWindowProc函數(shù)進(jìn)行處理。如果用戶想對(duì)系統(tǒng)鍵消息進(jìn)行處理,應(yīng)該在處理完這些消息后,再將其發(fā)送給DefWindowProc函數(shù),使得Windows系統(tǒng)能夠正常工作。
某些擊鍵消息可以被轉(zhuǎn)換成字符消息,例如字母鍵、數(shù)字鍵等。而有些鍵只能產(chǎn)生按鍵消息而沒(méi)有字符消息,例如 Shift鍵、Insert鍵等。消息循環(huán)中的 TranslateMessage函數(shù)可以實(shí)現(xiàn)從擊鍵消息向字符消息的轉(zhuǎn)化。當(dāng)GetMessage函數(shù)捕獲一個(gè)WM_SYSKEYDOWN消息或 WM_KEYDOWN消息后,TranslateMessage函數(shù)判斷產(chǎn)生該消息的鍵是否能夠被轉(zhuǎn)換成字符消息,如果能,就將該消息轉(zhuǎn)換成字符消息,再通過(guò)DispatchMessape函數(shù)將轉(zhuǎn)換后的字符消息發(fā)送到消息隊(duì)列中去。字符消息共有以下四種,如表所示。
字符 系統(tǒng)字符 非系統(tǒng)字符
普通字符 WM_SYSCHAR WM_CHAR
死字符 WM_SYSDEADCHAR WM_DEADCHAR
其中死字符是由某些特殊鍵盤(pán)上的按鍵所造成的,Windows一般忽略死字符所產(chǎn)生的消息。
Windows的消息一般是通過(guò)一個(gè)MSG結(jié)構(gòu)體變量傳送給消息處理函數(shù)的。對(duì)于鍵盤(pán)消息, MSG結(jié)構(gòu)體變量的各個(gè)域中較重要的是lParam域和 wParam域。wParam域用于保存按鍵的虛擬鍵代碼或字符的ASCII碼。對(duì)于非字符消息,wParam域保存按鍵的虛擬健代碼;對(duì)于字符消息, wParam域不保存字符的ASCII碼。lParam域則用于保存擊鍵時(shí)產(chǎn)生的附加信息,實(shí)際上一個(gè)32位的lParam變量被分為六部分,記錄了以下相關(guān)信息:重復(fù)次數(shù)、OEM掃描碼、擴(kuò)展鍵標(biāo)志、關(guān)聯(lián)鍵標(biāo)志、前一擊鍵狀態(tài)和轉(zhuǎn)換狀態(tài)。lParam域各位的含義如表所示。
位數(shù) 含義
擊鍵重復(fù)次數(shù)累加
OEM掃描碼
是否為擴(kuò)展鍵
未定義
是否便用關(guān)聯(lián)鍵,及Alt鍵是否同時(shí)按下。
前一次擊鍵狀態(tài),0表示該鍵前一次狀態(tài)為抬起,1表示前一次狀態(tài)為按下
轉(zhuǎn)換狀態(tài)
按鍵的次序不同,產(chǎn)生的消息也不相同。例如,按下并釋放1鍵,讀過(guò)程依次產(chǎn)生如表所示三條消息。按下1鍵所產(chǎn)生的消息和wParam的取值
消息 wParam變量取值
WM_KEYDOWN 虛擬碼1
WM_CHAR ASCII碼“1”
WM_KEYUP 虛擬碼1
如果按下Shift鍵后再按下1鍵并釋放,則依次產(chǎn)生如表所示的消息。按下 Shift鍵后按 1健所產(chǎn)生的消息和 wParam的取值
消息 wParam變量取值
WM_KEYDOWN 虛擬碼 VK_SHIFT
WM_KEYDOWN 虛擬碼 VK_1
WM_CHAR ASCII碼 “1”
WM_KEYUP 虛擬碼 VK_1
WM_KEYUP 虛擬碼 VK_SHIF
鍵盤(pán)應(yīng)用實(shí)例
下面通過(guò)一個(gè)應(yīng)用程序?qū)嵗齺?lái)說(shuō)明在實(shí)際編程中如何處理鍵盤(pán)消息。
#include
#include
// 全局變量
RECT rc; //記錄滾屏的矩形區(qū)域
?
int xChar, yChar; //文本輸入點(diǎn)坐標(biāo)
WNDCLASSEX wnd; //窗口類結(jié)構(gòu)變量
char szAppName = “鍵盤(pán)消息監(jiān)視程序”; //窗口類名
//函數(shù)聲明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance,int iCmdShow);
//函數(shù):WinMain
//作用:入口函數(shù)
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)
{
MSG msg;
if(!MyRegisterClass(hInstance))
{
return FALSE;
}
if(!InitInstance(hInstance,iCmdShow))
{
return FALSE;
}
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
//函數(shù):ShowKey
//作用:實(shí)現(xiàn)在窗口中顯示按鍵信息
void ShowKey (HWND hwnd, int iType,char *szMessage,WPARAM wParam,LPARAM lParam)
{
static char *szFormat ={“%-14s %3d %c %6u %4d %5s %5s %6s %6s”,
”%-14s %3d %c %6u %4d %5s %5s %6s %6s” };
char szBuffer;
HDC hdc;
ScrollWindowEx(hwnd, 0, -yChar, &rc,&rc,NULL,NULL,SW_INVALIDATE);
hdc = GetDC (hwnd);
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT));
TextOut (hdc,
xChar,
rc.bottom – yChar,
szBuffer,
wsprintf szBuffer,
szFormat,
szMessage, //消息
wParam, //虛擬鍵代碼
(BYTE) (iType ? wParam :‘ ’),//顯示字符值
LOWORD (lParam), // 重復(fù)次數(shù)
HIWORD (lParam) & 0xFF, // OEM鍵盤(pán)掃描碼
//判斷是否為增強(qiáng)鍵盤(pán)的擴(kuò)展鍵
(PSTR) (0x& lParam ? “是” : “否”),
//判斷是否同時(shí)使用了ALT鍵
(PSTR) (0x& lParam ? “是” : “否”),
(PSTR) (0x& lParam ? “按下” : “抬”),
//判斷前一次擊鍵狀
(PSTR)(0x& lParam ? “按下” : “抬起”))
//判斷轉(zhuǎn)換狀態(tài)?
);
ReleaseDC (hwnd, hdc); ?
ValidateRect (hwnd, NULL); ?
}
//函數(shù):WndProc
//作用:處理主窗口的消息
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static char szTop =”消息鍵 字符 重復(fù)數(shù) 掃描碼 擴(kuò)展碼 ALT 前一狀態(tài) 轉(zhuǎn)換狀態(tài)”;
static char szUnd =”_______ __ ____ _____ ______ ______ ___ _______ ______”;
//在窗口中輸出文字作為信息標(biāo)題
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
switch (iMsg)
{
case
hdc = GetDC (hwnd); //設(shè)定字體
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)); //檢取當(dāng)前字體的度量數(shù)據(jù)
GetTextMetrics (hdc, &tm);
xChar = tm.tmAveCharWidth;//保存字體平均寬度
yChar = tm.tmHeight; //保存字體高度
ReleaseDC (hwnd, hdc);
rc.top = 3 * yChar / 2;
return 0;
case
//窗體改變后保存新的滾屏區(qū)域右下角坐標(biāo)
rc.right = LOWORD (lParam);
rc.bottom = HIWORD (lParam);
UpdateWindow (hwnd);
return 0;
case WM_PAINT: //處理窗口重繪消息
InvalidateRect (hwnd, NULL, TRUE);
hdc = BeginPaint (hwnd, &ps);
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
SetBkMode (hdc, TRANSPARENT) ;
TextOut (hdc, xChar, yChar / 2, szTop, (sizeof szTop) – 1) ;
TextOut (hdc, xChar, yChar / 2, szUnd, (sizeof szUnd) – 1) ;
EndPaint (hwnd, &ps);
return 0;
case WM_KEYDOWN:
//處理鍵盤(pán)上某一鍵按下的消息
ShowKey (hwnd, 0, “WM_KEYDOWN”,wParam, lParam);
return 0;
case WM_KEYUP:
//處理鍵盤(pán)上某一按下鍵被釋放的消息
ShowKey (hwnd, 0, “WM_KEYUP”, wParam, lParam);
return 0;
case WM_CHAR:
//處理?yè)翩I過(guò)程中產(chǎn)生的非系統(tǒng)鍵的可見(jiàn)字符消息
howKey (hwnd, 1, “WM_CHAR”, wParam, lParam);
return 0;
case WM_DEADCHAR:
//處理?yè)翩I過(guò)程中產(chǎn)生的非系統(tǒng)鍵”死字符”消息
ShowKey (hwnd, 1, “WM_DEADCHAR”, wParam, lParam);
return 0;
case WM_SYSKEYDOWN:
//處理系統(tǒng)鍵按下的消息
ShowKey (hwnd, 0, “WM_SYSKEYDOWN”,wParam, lParam);
break;
case WM_SYSKEYUP:
//處理系統(tǒng)鍵抬起的消息
ShowKey (hwnd, 0, “WM_SYSKEYUP”, wParam, lParam);
break;
case
ShowKey (hwnd, 1, “WM_SYSCHAR”, wParam, lParam);
break;
case
ShowKey (hwnd, 1, “WM_SYSDEADCHAR”, wParam, lParam);
break;
case WM_DESTROY:
//處理結(jié)束應(yīng)用程序的消息
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}
//函數(shù):MyRegisterClass
//作用:注冊(cè)窗口類
BOOL MyRegisterClass(HINSTANCE hInstance)
{
wnd.cbSize= sizeof (wnd);
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = WndProc;
wnd.cbClsExtra = 0;
wnd.cbWndExtra = 0;
wnd.hInstance = hInstance;
wnd.hIcon = LoadIcon (NULL, IDI_APPLICATION);?
wnd.hCursor = LoadCursor (NULL, IDC_ARROW);
wnd.hbrBackground = (HBRUSH)
GetStockObject (WHITE_BRUSH);
wnd.lpszMenuName = NULL;
wnd.lpszClassName = szAppName;
wnd.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
return RegisterClassEx (&wnd);
}
//函數(shù):InitInstance
//作用:創(chuàng)建主窗口
BOOL InitInstance(HINSTANCE hInstance,int iCmdShow)
{
HWND hwnd;
hwnd = CreateWindow (szAppName,
“鍵盤(pán)消息監(jiān)視程序”,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL
);
if(!hwnd)
{
return FALSE;
}
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
return TRUE;
linux內(nèi)核如何打開(kāi)超線程
2.4以后的內(nèi)核都支持并且默認(rèn)開(kāi)啟。
通常握晌來(lái)說(shuō),超線程功能在bios里是默廳友認(rèn)開(kāi)啟的,
如果你cpu支持超線程,則會(huì)自動(dòng)模擬為物理扮皮槐核心x2;
如果超線程沒(méi)有開(kāi)啟,可以在開(kāi)機(jī)的時(shí)候,進(jìn)入bios里,找hyper-threading項(xiàng),改為enabled就是開(kāi)啟超線程
只要BIOS把超線程打開(kāi),Linux 2.4以后的內(nèi)核都支持并且默認(rèn)開(kāi)啟
首先要在BIOS里面打開(kāi)超線程支持,然后在Linux內(nèi)核的Config中打開(kāi)超線程就可以了。
linux手冊(cè)翻譯——pthread_setname_np()
pthread_setname_np, pthread_getname_np :設(shè)置昌滑/獲取線程的名稱
編譯兄迅歷和鏈接需要參數(shù) : -pthread
默認(rèn)情況下,所有使用 pthread_create() 創(chuàng)建的線程都繼承程序名稱。 pthread_setname_np() 函數(shù)可用于為線程設(shè)置唯一名稱,這對(duì)于調(diào)試多線程應(yīng)用程序非常有用。 線程名稱是一個(gè)有意義的 C 語(yǔ)言字符串,包括終止空字節(jié) (‘\0’)在內(nèi),其長(zhǎng)度限制為 16 個(gè)字符。
thread
參數(shù)指定要更改名稱的線程;
name
指定新名稱。
pthread_getname_np() 函數(shù)可用于獲取線程的名稱。
thread
參數(shù)指定線程。 緩沖區(qū)
name
用于存放返回的線程名稱; len 指定緩沖區(qū)的可用字節(jié)數(shù)。 區(qū)長(zhǎng)度至少應(yīng)為 16 個(gè)字符。 輸出緩沖區(qū)中返回的線程名稱將以空 (‘\0’)終止。
成功時(shí),這些函數(shù)返回 0; 出錯(cuò)時(shí),它們返回一個(gè)非零錯(cuò)誤號(hào)。
pthread_setname_np() 函數(shù)可能會(huì)失敗并出現(xiàn)以下錯(cuò)誤:
ERANGE
name 指定的字符串長(zhǎng)度超過(guò)了允許的限制。
pthread_setname_np() 函數(shù)可能會(huì)失敗并出現(xiàn)以下錯(cuò)誤:
ERANGE
name 和 len 指定的緩沖區(qū)太小,無(wú)法容納線程名稱。
如果這些函數(shù)中的任何一個(gè)無(wú)法打開(kāi) /proc/self/task//comm,則調(diào)用可能會(huì)失敗并出現(xiàn) open(2) 中描述的錯(cuò)誤之一。(見(jiàn)NOTES)
從實(shí)現(xiàn)上講羨搜,pthread_setname_np()將線程的名稱寫(xiě)入到了/proc FS的comm文件:/proc/self/task//comm.
關(guān)于多線程調(diào)試 linux的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開(kāi)發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
分享題目:「指南」多線程調(diào)試Linux:技巧大全(多線程調(diào)試linux)
本文來(lái)源:http://www.dlmjj.cn/article/dpijeje.html


咨詢
建站咨詢
