原為某軟件公司試題,大意如下:對于給定的有符號32位整數,寫一個函數,當該數為正數時返回1,為負數時返回-1,為零時返回零,要求不能使用任何的條件判斷分支跳轉語句。在這里,稍微擴展了一下,給出了對應無符號32位整數的情形。解決思路是符號位和值分開處理,對于有符號32位整數,符號位右移31位即得a,若為非負數則a=0x00000000,否則a=0xFFFFFFFF;然后將值部分各位的值(0或1)不斷縮小合并到一位中去得到b,這是針對0和正數的情況處理,再將a和b位或即可。C++代碼描述如下
1
//若val為0則返回0, val為負數則返回-1, 為正數返回1
2
int32_t check32(int32_t val)
3

{
4
int32_t a = val >> 31;
5
int32_t b = (val & 0x0000FFFF) | ((val >> 16)&0x0000FFFF);
6
b = (b & 0x000000FF) | ((b >> 8)&0x000000FF);
7
b = (b & 0x0000000F) | ((b >> 4)&0x0000000F);
8
b = (b & 0x00000003) | ((b >> 2)&0x00000003);
9
b = (b & 0x00000001) | ((b >> 1)&0x00000001);
10
return a|b;
11
}
12
13
//若val為0則返回0, 否則返回1
14
uint32_t check32(uint32_t val)
15

{
16
uint32_t a = (val & 0x0000FFFF) | ((val >> 16)&0x0000FFFF);
17
a = (a & 0x000000FF) | ((a >> 8)&0x000000FF);
18
a = (a & 0x0000000F) | ((a >> 4)&0x0000000F);
19
a = (a & 0x00000003) | ((a >> 2)&0x00000003);
20
a = (a & 0x00000001) | ((a >> 1)&0x00000001);
21
return a;
22
}
若哪位有更好的解法,還望多多分享
posted @
2011-06-18 23:50 春秋十二月 閱讀(3397) |
評論 (0) |
編輯 收藏
WTL是窗口模板庫(Windows Library Template)的簡稱,是一套輕量級C++ GUI庫,因為它使用了C++模板封裝了窗口界面操作API和消息映射處理,它擴展了ATL中的UI窗口部分,并支持如下更多的功能特性: (1) 對話框和通用控件:包括對話框數據交換(DDX),子類化,控件消息通知與反射等 (2) 工具欄和狀態欄:包括工具條UI狀態更新,多窗格狀態條及UI狀態更新等 (3) 分隔窗口:包括窗格容器,嵌套分隔,特殊繪制等 (4) 屬性頁和向導:包括屬性表,普通屬性頁,向導屬性頁等 (5) GDI類等:包括GDI封裝類,通用對話框等 (6) 使用ActiveX控件:包括使用控件類,調用控件的方法,控件事件映射處理等 (7) 高級對話框UI類:包括自繪和外觀定制類,新控件類,控件UI狀態更新,對話框數據驗證DDV等 (8) 支持拖放操作:包括拖放接口實現類,最近使用文件列表等 綜上所述,使用WTL幾乎可以實現MFC所能實現的功能與界面,而且生成的執行文件體積更小,不需要動態鏈接庫就可直接快速地執行。
根據WIN32窗口原理,當事件發生的時候,一般由父窗口接收其子窗口或控件的通知或命令消息,在這里父窗口是消息接收者,子窗口或控件是消息發送者,那么誰是消息處理者呢?實際上由誰來處理消息只是代碼上的邏輯,既可以在父窗口的窗口過程回調內處理,也可以在子窗口或控件的窗口過程回調內處理,在哪處理更方便合理就在哪處理,如果是在子窗口或控件窗口過程回調內處理,那么就需要作額外的處理了,也就是在父窗口中將消息反射給發送者,進而再由發送者處理。下面以父窗口為打開文件對話框,雙擊它的列表視圖控件為例,給出運用上面(1)中的控件消息通知與反射來處理NM_DBLCLK消息的兩種實現方式。
繼承方式:由控件處理消息 從CWindowImpl模板基類派生一個子窗口或控件子類即listview子類,添加消息映射項和消息處理函數,消息映射項用REFLECTED_NOTIFY_XXX或REFLECTED_COMMAND_XXX系列反射宏實現,具體使用哪個宏,決定于是否通知或命令消息,及消息對應的ID和通知碼。
1
class CFileListViewCtrl : public CWindowImpl<CFileListViewCtrl, CListViewCtrl>
2

{
3
protected:
4
BEGIN_MSG_MAP(CFileListViewCtrl)
5
REFLECTED_NOTIFY_CODE_HANDLER_EX(NM_DBLCLK,OnListViewDblclk) //反射通知消息處理宏
6
CHAIN_MSG_MAP(CListViewCtrl)
7
END_MSG_MAP()
8
LRESULT OnListViewDblclk(NMHDR* pNMHDR); //消息響應處理函數
9
};
在父窗口類消息映射鏈中最后添加反射通知宏REFLECT_NOTIFICATIONS()項。
1
class COpenFileDlg : public CDialogImpl<COpenFileDlg> , public CWinDataExchange<COpenFileDlg>
2

{
3
public:
4
COpenFileDlg();
5
~COpenFileDlg();
6
enum { IDD = IDD_OPEN_FILE_DLG };
7
8
protected:
9
BEGIN_MSG_MAP(COpenFileDlg)
10
MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11
REFLECT_NOTIFICATIONS() //消息反射通知宏
12
END_MSG_MAP()
13
14
BEGIN_DDX_MAP(COpenFileDlg)
15
DDX_CONTROL(IDC_LIST_FILE,m_list_File)
16
END_DDX_MAP()
17
18
LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
19
20
private:
21
CFileListViewCtrl m_list_File; //使用派生類實例作為成員變量
22
};
成員方式:由父窗口處理消息
直接使用ATL中的包含窗口模板類CContainedWindowT,參數為子控件的類名即listviewctrl,實例化為父窗口類的一個成員變量,在父窗口類消息映射鏈中添加ALT_MSG_MAP宏來實現消息分派,其參數為分派ID,這個ID為成員變量初始化時指定的常量;添加反射通知宏REFLECT_NOTIFICATIONS(),注意ALT_MSG_MAP宏必須在反射通知宏REFLECT_NOTIFICATIONS之后。
1
class COpenFileDlg : public CDialogImpl<COpenFileDlg> , public CWinDataExchange<COpenFileDlg>
2

{
3
public:
4
COpenFileDlg();
5
~COpenFileDlg();
6
enum { IDD = IDD_OPEN_FILE_DLG };
7
8
protected:
9
BEGIN_MSG_MAP(COpenFileDlg)
10
MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)
11
REFLECT_NOTIFICATIONS() // 消息反射通知宏
12
ALT_MSG_MAP(1) // 消息分派宏
13
REFLECTED_NOTIFY_CODE_HANDLER_EX(NM_DBLCLK,OnListViewDblclk) // 反射通知消息處理宏
14
END_MSG_MAP()
15
16
BEGIN_DDX_MAP(COpenFileDlg)
17
DDX_CONTROL(IDC_LIST_FILE,m_list_File)
18
END_DDX_MAP()
19
20
LRESULT OnInitDialog(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandle);
21
LRESULT OnListViewDblclk(NMHDR* pNMHDR); //消息響應處理函數
22
private:
23
CContainedWindowT<CListViewCtrl> m_list_File; // 實例化包含窗口模板類作為成員變量
24
};
在父窗口內需要初始化m_list_File以指定分派ID號。
1
COpenFileDlg:: COpenFileDlg():2
m_list_File(this,1) // 指定消息分派ID為1
3

{
4
}
posted @
2010-06-14 17:50 春秋十二月 閱讀(6028) |
評論 (0) |
編輯 收藏
MFC將windows消息系統進行了高度的抽象和封裝,其根本原理是運用C++的高級特性并結合一定的設計模式(如工廠模式,模板方法等)來實現的。一般的windows消息(WM_XXX),則一定是由派生類流向基類,沒有旁流的可能。如果是命令消息(WM_COMMAND),那就有比較奇特的路線了。下面就針對多文檔/單文檔(Document-View)、對話框兩種應用程序比較討論WM_COMMAND消息的傳遞處理過程。討論前首先得明確命令消息的來源,命令消息一般是用戶選擇某個菜單項,或一個加速鍵被翻譯,或一個子控件發送一個通知消息給它的父窗口時產生的。對一個菜單而言,消息接收者是Frame窗口或擁有它的對話框;對一個工具欄而言,消息接收者是它的父窗口。兩種應用程序命令消息處理流程如下圖所示。
從上圖可知,文檔視圖型的處理路線是先向下再向上,而對話框型的路線是一直向上,消息接收者只有一個,而處理者次序有多個,每個處理者內部首先都是調用根基類CCmdTarget的OnCmdMsg虛函數,在這個函數內逐級向基類遍歷消息映射表,根據命令ID和通知碼找到對應的消息映射結構體AFX_MSGMAP_ENTRY,如果找到再處理這個命令消息,否則返回FALSE,退回到this對象所在的OnCmdMsg函數進行下一步處理。如果到最后一層都沒有找到對應命令的消息映射,則返回到系統的默認處理DefWindowProc。再綜合考慮下,如果一個對話框接收到了一個命令消息例如是點擊它的子控件工具欄某個按鈕發出的,而這個對話框類沒有添加相應的ON_COMMAND映射,就會進入到它的父窗口類OnCmdMsg函數進行處理,如果這個父窗口正好是Frame窗口,那么命令消息的處理流程就由上圖右邊轉到左邊了。而最終命令消息能否得處理,就看上圖5種對象(Frame、View、Document、Dialog、App、Thread)是否添加了對應的ON_COMMAND映射。
到此為止,我們已經明確了WM_COMMAND消息的處理流程,但是發現最終處理卻是由收到消息的窗口傳遞的,不是消息通知者自己處理的,有的時候為了提高代碼的封裝性,可能需要自己處理這些命令比較方便,比如有一個工具欄CPlayToolBar子類從CToolBar繼承,有播放、暫停、停止3個按鈕,它的父窗口是CPlayDialog對話框。按照常規,這3個按鈕命令事件的處理一般是在CPlayDialog類中3個ON_COMMAND映射宏和處理函數的,但如果在CPlayToolBar類中添加3個ON_COMMAND映射宏和處理函數,是得不到處理的,其原因在于對話框型的路線是一直向上,再者MFC中沒有對應的命令反射ON_COMMAND_REFLECT這個宏。為了能使CPlayToolBar類自己處理這3個按鈕命令事件,就需要從CPlayDialog類中轉移路線,使之流向其子窗口工具欄,這樣CPlayToolbar 類就得到了自己處理的機會。具體操作是重載CPlayToolBar和CPlayDialog的OnCommand虛函數, CPlayDialog代碼如下所示:
1 BOOL CPlayDialog::OnCommand(WPARAM wParam, LPARAM lParam)

2
{
3 if (lParam==(LPARAM)m_playtoolbar.m_hWnd)

4
{
5 m_playtoolbar.OnCommand(wParam,lParam); //m_playtoolbar為CPlayToolBar對象,注意使OnCommand成為公有成員
6 }
7 else

8
{
9 return CDialog::OnCommand(wParam, lParam);
10 }
11 } CPlayToolBar類代碼如下所示
1 BEGIN_MESSAGE_MAP(CPlayToolBar, CToolBar)
2 ON_COMMAND(ID_PLAY, Play)
3 ON_COMMAND(ID_PAUSE, Pause)
4 ON_COMMAND(ID_STOP, Stop)
5 END_MESSAGE_MAP()
6
7 void CPlayToolBar::Play()

8
{
9 }
10 void CPlayToolBar::Pause()

11
{
12 }
13 void CPlayToolBar::Stop()

14
{
15 } 現在,3個按鈕命令事件能在CPlayToolBar類中獨立處理了,這樣一來就提高了代碼的封裝性,簡化了父窗口CPlayDialog類的處理。
posted @
2009-12-19 21:29 春秋十二月 閱讀(6082) |
評論 (1) |
編輯 收藏
最近在工作中,寫一計算桿塔絕緣子中心點的GPS坐標程序時,定義了一結構,里面用到了string類型來存儲桿塔所屬線路號、桿塔號,桿塔模型名稱。代碼如下:
1
/*
2
@brief 桿塔信息結構
3
*/
4
typedef struct _TOWER_INFO
5

{
6
string strLineNo; ///< 線路號
7
string strTowerNo; ///< 桿塔號
8
string strTowerType; ///< 桿塔類型
9
double dDangDistance; ///< 檔距
10
double dHCHeight; ///< 呼稱高
11
double dLongitude; ///< 經度
12
double dLatitude; ///< 緯度
13
double dAltitude; ///< 海拔高度
14
double dLineCorners; ///< 線路轉角
15
long lCornerDirection; ///< 左轉還是右轉: 0不轉, 1左轉, 2右轉
16
vector<INSULATOR_INFO::CENTER_POINT_INFO> vecInsulatorCenterPointInfo; ///< 桿塔所有絕緣子中心點信息
17
_TOWER_INFO()
{ memset(this, 0, sizeof(_TOWER_INFO)); } //該行代碼可能會引起string內存泄露
18
19
}TOWER_INFO,*PTOWER_INFO; 在后面對該結構的string型變量有賦值操作, 代碼如下
1
......
2 TOWER_INFO cur_tower_center_info;
3
cur_tower_center_info.strLineNo = sheetLine->Cell(i, 2)->GetText(); //調度碼
4
cur_tower_center_info.strTowerNo = sheetLine->Cell(i, 7)->GetText(); //桿塔號
5
cur_tower_center_info.strTowerType = sheetLine->Cell(i, 8)->GetText(); //桿塔類型
6 ...... 運行程序,待程序結束后,發現有內存泄露,提示信息如下
1
Detected memory leaks!
2
Dumping objects ->
3

{235250} normal block at 0x01774A60, 16 bytes long.
4
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
5

{235237} normal block at 0x01774CB0, 16 bytes long.
6
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
7

{235234} normal block at 0x01774A10, 16 bytes long.
8
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
9

{235184} normal block at 0x01774200, 16 bytes long.
10
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
11

{235171} normal block at 0x01774450, 16 bytes long.
12
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
13

{235168} normal block at 0x017741B0, 16 bytes long.
14
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
15

{235118} normal block at 0x017739A0, 16 bytes long.
16
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
17

{235105} normal block at 0x01773BF0, 16 bytes long.
18
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
19
.. 經過一番源代碼跟蹤調試后,發現原因在于TOWER_INFO結構體的構造函數內調用了memset(this, 0, sizeof(_TOWER_INFO);使得string內部指針_Bx._Ptrr值為0,_Myres為0,在這種情況下當string對象被賦值為小字符串(字節數包括結束符小于等于16的字符串)時,因新申請的內存在后來得不到釋放,所以這塊內存被泄露了,根據string類內存管理算法(ms vc版本)得知這塊內存大小總是16個字節.但當被賦值為大字符串(字節數包括結束符大于16的字符串)時,反而沒有內存泄露,這是因為新申請的內存在析構或下次賦值時總能被釋放.
從該泄露問題的分析解決過程中,總結得到規律:不要輕易零初始化string, vector等stl標準容器及具有動態內存管理的類。
posted @
2009-08-07 01:31 春秋十二月 閱讀(7733) |
評論 (19) |
編輯 收藏
上次介紹了一種字符串轉化為16進制顯示的算法,并封裝成了API,這個API可用于串口收到數據后按16進制顯示字符串,這次介紹串口按16進制發送字符串的算法,使用基于字符類型參數的模板函數實現。算法原理是遍歷字符串,將在區間'0'--'9','A'--'F','a'--'f'的字符轉化成對應的16進制整數(范圍為閉區間0-15),如遇到連續2個可以轉換的字符,則將它們存儲在一個無符號字節內,如遇到不能轉化的字符,則略過繼續。代碼如下:
1
/**//**
2
@brief 將字符轉化為對應的10進制數整數 ASCII版本
3
* 若字符不能轉化則返回-1
4
*/
5
template<typename charT>
6
inline char ConvertHexChar(charT ch)
7

{
8
if(ch>=(charT)'0'&&ch<=(charT)'9')
9
return ch-(charT)'0';
10
else if(ch>=(charT)'A'&&ch<=(charT)'F')
11
return ch-(charT)'A'+10;
12
else if(ch>=(charT)'a'&&ch<=(charT)'f')
13
return ch-(charT)'a'+10;
14
else
15
return -1;
16
}
17
18
typedef std::vector<unsigned char> CByteArrayEx;
19
20
/**//**
21
@brief 將字符串轉化成對應的16進制數形式存儲
22
@param template charT 源字符類型
23
@param src 源數據串
24
@param size 要轉換的長度,字符數
25
@param ByteArray 存放結果的字節數組
26
27
* 如字符串80 12 34 46 AD FF,對應的就是0x80,0x12,0x34,0x46,0xAD,0xFF
28
該函數會自動過濾不能轉換的字符,可轉換字符范圍在0--9,a--f,A--F區間
29
*/
30
template<typename charT>
31
inline void StrToHex(const charT* src,size_t len,CByteArrayEx& ByteArray)
32

{
33
char low = -1, high = -1;
34
for (size_t n = 0; n < len; )
35
{
36
high = ConvertHexChar(src[n++]);
37
if (-1 == high)
38
{
39
continue;
40
}
41
if (n >= len)
42
{
43
ByteArray.push_back(high);
44
break;
45
}
46
low = ConvertHexChar(src[n++]);
47
if (-1 == low)
48
{
49
ByteArray.push_back(high);
50
continue;
51
}
52
ByteArray.push_back(high * 16 + low);
53
}
54
}
55
56
/**//**
57
@brief 將字符串轉化成對應的16進制數形式存儲
58
@param template charT 源字符類型
59
@param src 源數據串
60
@param ByteArray 存放結果的字節數組
61
*/
62
template<typename charT>
63
inline void StrToHex(const charT* src,CByteArrayEx& ByteArray)
64

{
65
StrToHex(src,select_variable<is_ansi_char<s_charT>::value>(strlen,wcslen)(src),ByteArray);
66
}
posted @
2009-07-12 16:58 春秋十二月 閱讀(3104) |
評論 (0) |
編輯 收藏
最近在項目中調試串口,,總結封裝了字符串轉化為16進制顯示的算法,串口數據發送一般為ASCII和16進制兩種,當收到數據時數據也有ASCII和16進制顯示兩種方式,下面給出一種轉化算法,該算法基于字符類型參數化的模板實現,字符串的轉化只是調用其內存版本,算法原理是對字符串內存進行操作轉化,以一個字節(unsigned char類型)為單位,分別取其高4位和低4位(范圍為0x0--0xF), 轉化為對應的目標字符('0'--'F')顯示,代碼如下
1
/**//**
2
@brief MemToHex
3
@param template charT 字符類型
4
@param src 源緩沖區
5
@param size lpSrc指向數據的大小,字節數
6
@param tag 顯示分隔符,默認為0表示空字符
7
@return 返回轉化后16進制字符串
8
*/
9
template<typename charT>
10
inline std::basic_string<charT> MemToHex(const void* src, size_t size, bool upper = true,charT tag = 0)
11

{
12
std::basic_string<charT> strDest;
13
strDest.reserve(2*size);
14
15
unsigned char* pSrc = (unsigned char*)src;
16
unsigned char buf[2];
17
18
for (size_t i = 0; i < size; ++i)
19
{
20
unsigned char c0 = *pSrc >> 4;
21
if ( c0 >= 0x0 && c0 <= 0x9)
22
buf[0] = c0 - 0 + '0';
23
else
24
buf[0] = c0 - 10 + (upper ? 'A' : 'a');
25
26
unsigned char c1 = *pSrc++ & 0x0F;
27
if ( c1 >= 0x0 && c1 <= 0x9)
28
buf[1] = c1 - 0 + '0';
29
else
30
buf[1] = c1 - 10 + (upper ? 'A' : 'a');
31
32
strDest += (charT)buf[0];
33
strDest += (charT)buf[1];
34
if (tag != 0) strDest += tag;
35
}
36
return strDest;
37
}
38
39
/**//**
40
@brief StrToHex
41
@param template d_charT 目標字符類型
42
@param template s_charT 源字符類型
43
@param src 源字符串
44
@param upper true表示大寫,false表示小寫
45
@param tag 顯示分隔符,默認為0表示空字符
46
@return 返回轉化后16進制字符串
47
*/
48
template<typename d_charT,typename s_charT>
49
inline std::basic_string<d_charT> StrToHex(const s_charT* src, bool upper = true,d_charT tag = 0)
50

{
51
return MemToHex(src,select_variable<is_ansi_char<s_charT>::value>(strlen,wcslen)(src)*sizeof(s_charT),upper,tag);
52
} 在應用中需要轉化時, 只需調用StrToHex函數,示例如下:
1
string strDest1 = StrToHex<char>("123456789漢字ABCXYZ");
2
wstring wstrDest1 = StrToHex<wchar_t>("123456789漢字ABCXYZ",true,' ');
3
string strDest2 = StrToHex<char>(L"123456789漢字ABCXYZ");
4
wstring wstrDest2 = StrToHex<wchar_t>(L"123456789漢字ABCXYZ", true,L',');
5
6
TRACE4("%s \n", strDest1.c_str());
7
TRACE4(L"%s \n", wstrDest1.c_str());
8
TRACE4("%s \n", strDest2.c_str());
9
TRACE4(L"%s \n", wstrDest2.c_str()); 結果輸出如下:
1
313233343536373839BABAD7D641424358595A
2
31 32 33 34 35 36 37 38 39 BA BA D7 D6 41 42 43 58 59 5A
3
310032003300340035003600370038003900496C575B410042004300580059005A00
4
31,00,32,00,33,00,34,00,35,00,36,00,37,00,38,00,39,00,49,6C,57,5B,41,00,42,00,43,00,58,00,59,00,5A,00,
posted @
2009-06-27 13:08 春秋十二月 閱讀(12856) |
評論 (6) |
編輯 收藏
在WINDOWS NT4.0 以上操作系統中,串口通訊有2種模式:同步方式和異步方式。由
CreateFile中的
dwFlagsAndAttributes參數決定,
若指定FILE_FLAG_OVERLAPPED標志則為異步方式,否則為同步方式。當為同步模式時,調用ReadFile或WriteFile會阻塞調用線程直到讀完或寫完指定量的數據才返回,這樣就有可能出現無法退出程序的現象,解決方法是為讀寫操作設置超時,注意這種超時指的是ReadFile或WriteFile函數的返回時間,僅對同步模式有效。代碼如下
1
//以下m_pComPort為本人自己封裝的C++串口類CComPort的指針
2
3
// FALSE表示以同步方式打開
4
m_pComPort->Open(2, FALSE, 38400);
5
6
//設置讀寫超時為5秒
7 COMMTIMEOUTS timeout = { 0 };
8
timeout.ReadTotalTimeoutConstant = 5000;
9
timeout.WriteTotalTimeoutConstant = 5000;
10
m_pCommPort->SetTimeouts(timeout);
11
12 char szData[1024] = { 0 };
13
//讀數據
14
DWORD dwRet = m_pCommPort->ReadComm(szData, 1024);
15
//寫數據
16
dwRet = m_pCommPort->WriteComm(szData, 1024);
17
//關閉串口
18
m_pCommPort->Close();
當為異步模式時,由于讀寫操作會立即返回,因此設置超時指的是設置等待操作完成的時間,而不是
ReadFile或
WriteFile函數返回的時間,代碼如下
1
//以下m_pComPort為本人自己封裝的C++串口類CComPort的指針
2
3
// TRUE表示以異步方式打開
4
m_pComPort->Open(2, TRUE, 38400);
5
6
//設置讀寫等待超時為5秒
7 char szData[1024] = { 0 };
8
9
//當第3個參數為0時,讀寫操作會立即返回
10
//讀數據
11
DWORD dwRet = m_pCommPort->ReadComm(szData, 1024, 5000);
12
//寫數據
13
dwRet = m_pCommPort->WriteComm(szData, 1024, 5000);
14
//關閉串口
15
m_pCommPort->Close();
這里的
ReadComm和
WriteComm的實現內部針對不同模式作了不同處理,異步模式時即調用了
WaitForSingleObject等待函數來設置超時。同步模式時即調用不帶重疊結構的
ReadFile或
WriteFile函數來接收或發送指定量的數據。另外在這介紹下串口虛擬軟件vspd,這個軟件能模擬在同一臺計算機上進行兩個串口的通訊,有利于沒有實際設備情況下的串口調試。
posted @
2009-04-17 19:15 春秋十二月 閱讀(4473) |
評論 (0) |
編輯 收藏
首先聲明,這里的工作線程與UI線程是相對的,即沒有任何窗口的。如果需要與主線程或其它輔助線程通訊,有幾種方法如事件、消息和信號等,也可以是以上幾種方法的綜合運用。下面就列出以下3種通訊方法的代碼框架。
只用消息通訊
1
DWORD ThreadProc(LPVOID lParam)
2
{
3
//創建線程消息隊列
4
MSG msg;
5
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
6
//通知其它線程消息隊列已創建好
7
SetEvent(hEvent);
8
9
while(true)
10
{
11
GetMessage(&msg, NULL, 0, 0);
12
switch(msg.message)
13
{
14
case WM_QUIT:
15
return 1;
16
17
//自定義消息1處理
18
case WM_USER + 100:
19
break;
20
21
//自定義消息2處理
22
case WM_USER + 101:
23
break;
24
}
25
}
26
return 0;
27
}
只用事件通訊
1
DWORD ThreadProc(LPVOID lParam)
2
{
3
DWORD dwIndex;
4
while (true)
5
{
6
dwIndex = WaitForMultipleObjects(cObjects, pObjects, FALSE, INFINTE);
7
if (WAIT_OBJECT + 0== dwIndex)
8
{
9
return 1; //假設為退出事件
10
}
11
else if (WAIT_OBJECT + 1 == dwIndex)
12
{
13
//事件1受信,處理之
14
}
15
16
else if (WAIT_OBJECT + cObjects - 1 == dwIndwx)
17
{
18
//事件cObjects - 1受信, 處理之
19
}
20
}
21
}
用消息和事件通訊
1
DWORD ThreadProc(LPVOID lParam)
2
{
3
while (TRUE)
4
{
5
DWORD ret ;
6
MSG msg ;
7
8
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
9
{
10
switch(msg.message)
11
{
12
//線程退出消息,直接返回
13
case WM_QUIT:
14
return 1;
15
16
//自定義消息1處理
17
case WM_USER + 100:
18
break;
19
//自定義消息2處理
20
case WM_USER + 101:
21
break;
22
}
23
}
24
ret = MsgWaitForMultipleObjects(cObjects, lphObjects, FALSE,INFINITE,QS_POSTMESSAGE);
25
if (ret == (WAIT_OBJECT_0 + cObjects))
26
{
27
//有新的消息到來,繼續到上步PeekMessage處理
28
continue;
29
}
30
else
31
{
32
//是事件受信了
33
if (ret == WAIT_OBJECT_O)
34
{
35
}
36
else if (ret == WAIT_OBJECT_O + 1)
37
{
38
}
39
else if(ret == WAIT_OBJECT_O + cObjects - 1)
40
{
41
}
42
}
43
return 0;
44
} 上面用到了GetMessage和PeekMessage 函數,這兩者都是從消息隊列取出消息,不同的是GetMessage從消息隊列刪除消息,并且阻塞調用線程。PeekMessage則是查詢消息隊列,如果有消息就取出,沒有消息也立即返回,是否從消息隊列刪除消息由最后一個參數決定:PM_REMOVE表示刪除,PM_NOREMOVE表示不刪除。可以簡單地認為,GetMessage是同步的,PeekMessage是異步的。
posted @
2009-04-15 18:11 春秋十二月 閱讀(6393) |
評論 (5) |
編輯 收藏
ACE中的同步機制是輕量級高效的,它不同于MFC中的同步類,MFC中的同步類采用了類繼承的方式,而ACE并沒有用繼承方式,各個不同的鎖類是平行的關系,這些類支持相同的接口,即它們的所有公共方法是相同的,因此可被適配用于動態綁定和替換,這種動態綁定是沒有虛函數調用開銷的,且這些方法代碼短小使用了內聯實現。應用程序開發者可以通過指定模板實參來使用不同的鎖,并可在運行時動態替換。
ACE中的鎖是易于使用的,既有互斥鎖(ACE_Mutex)又有讀寫鎖(ACE_RW_Mutex),這些鎖又細分為專門用于線程同步(ACE_Thread_Mutex,ACE_RW_Thread_Mutex)和進程(ACE_Process_Mutex,ACE_RW_Process_Mutex)同步的特定鎖。相比MFC高級的是ACE中還提供了遞歸互斥體(ACE_Token),可有效地用于某些遞歸例程。
ACE中提供了ACE_Lock鎖抽象基類和ACE_Adapter_Lock鎖適配器模板類,ACE_Adapter_Lock從ACE_Lock繼承,實現了動態綁定和替換。另外,ACE還提供了ACE_Atomic_Op模板類,重載了基本的算術運算符,實現了原子化算術運算。
posted @
2009-04-02 16:33 春秋十二月 閱讀(2050) |
評論 (1) |
編輯 收藏