MFC(線程同步與異步套接字,孫鑫C++第十六講札記整理)
提問者: yaozhi3333 發(fā)布時間:2014-06-26 瀏覽:66 回復:0 懸賞:0.0希賽幣
MFC(線程同步與異步套接字,孫鑫C++第十六講筆記整理)
1.事件對象:來實現(xiàn)線程的同步。與互斥對象一樣均屬于內(nèi)核對象。
當人工重置有信號時,所有線程均得到信號,所以不能設為人工重置。代碼就不貼了,通過創(chuàng)建匿名的事件對象,也可以讓一個程序只能運行一個實例。
2.關鍵代碼段實現(xiàn)線程的同步:類似公用電話亭,只有當電話亭里面沒人了,其它人才可以再進去打電話。用了4個函數(shù),這種方法比較簡單!但缺點是如果使用了多少關鍵代碼碼,容易贊成線程的死鎖
3.線程死鎖,用關鍵代碼示例,用了兩個臨界區(qū)對象,實戰(zhàn)中要注意避免這種錯誤!
4.使用異步套接字編寫網(wǎng)絡聊天室
1)加載套接字庫,進行版本協(xié)商,包含頭文件,鏈接庫文件,這次請示的是2.2版本!
2)在類CChatDlg中增加一個成員變量m_socket,在析構函數(shù)中釋放這個變量
3)利用WSASocket()創(chuàng)建套接字(數(shù)據(jù)報類型的UDP型的)
4)然后調(diào)用WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ)為網(wǎng)絡事件定義消息!此時如果發(fā)生FD_READ消息,系統(tǒng)會發(fā)送UM_SOCK消息給應用程序!程序并不會阻塞在這兒了!
以上是在BOOL CChatDlg::OnInitDialog()完成
5)然后完成消息響應!
頭文件中:#define UM_SOCKWM_USER+1
afx_msg void OnSock(WPARAM,LPARAM);
源文件中:
ON_MESSAGE(UM_SOCK,OnSock)
實現(xiàn)消息響應函數(shù):void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ:
WSABUF wsabuf;
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwRead;
DWORD dwFlag=0;
SOCKADDR_IN addrFrom;
int len=sizeof(SOCKADDR);
CString str;
CString strTemp;
HOSTENT *pHost;
if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,
(SOCKADDR*)&addrFrom,&len,NULL,NULL))
{
MessageBox("接收數(shù)據(jù)失??!");
return;
}
pHost=gethostbyaddr((char*)&addrFrom.sin_addr.S_un.S_addr,4,AF_INET);
//str.Format("%s說 :%s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str.Format("%s說 :%s",pHost->h_name,wsabuf.buf);
str+="\r\n";
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
break;
}
}
OK!
6)完成數(shù)據(jù)發(fā)送的功能!
void CChatDlg::OnBtnSend()
{
// TOD Add your control notification handler code here
DWORD dwIP;
CString strSend;
WSABUF wsabuf;
DWORD dwSend;
int len;
CString strHostName;
SOCKADDR_IN addrTo;
HOSTENT* pHost;
if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=="")
{
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
}
else
{
pHost=gethostbyname(strHostName);
addrTo.sin_addr.S_un.S_addr=*((DWORD*)pHost->h_addr_list[0]);
}
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000); GetDlgItemText(IDC_EDIT_SEND,strSend);
len=strSend.GetLength();
wsabuf.buf=strSend.GetBuffer(len);
wsabuf.len=len+1; SetDlgItemText(IDC_EDIT_SEND,""); if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0,
(SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))
{
MessageBox("發(fā)送數(shù)據(jù)失??!");
return;
}
}7)完成將主機名轉換為IP地址的功能,以前將IP地址轉換為主機名的功能,單線程的聊天室創(chuàng)建完畢!性能并且非常出色!
下面是一些具體的代碼:
#include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1( LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; HANDLE hEvent; int main() { HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL); HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL); hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);//自動,有信號 CloseHandle(hThread1); CloseHandle(hThread2); Sleep(4000); return 0; } DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ) { while(TRUE) { SetEvent(hEvent); WaitForSingleObject(hEvent,INFINITE); if(tickes>0) { cout$amp;
//CreateEvent設置自定的,并且初始有信號 /*#include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1( LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; HANDLE hEvent; int main() { HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL); HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL); hEvent=CreateEvent(NULL,FALSE,TRUE,NULL);//自動,有信號 CloseHandle(hThread1); CloseHandle(hThread2); Sleep(4000); return 0; } DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ) { while(TRUE) { WaitForSingleObject(hEvent,INFINITE); if(tickes>0) { cout$amp;
//CreateEvent手動,一開始就無信號 /*#include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1( LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; HANDLE hEvent; int main() { HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL); HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL); hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);//手動,無信號 SetEvent(hEvent); CloseHandle(hThread1); CloseHandle(hThread2); Sleep(4000); return 0; } DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ) { while(TRUE) { WaitForSingleObject(hEvent,INFINITE); if(tickes>0) { cout$amp;
//關鍵代碼段,臨界區(qū)域 //如果只是Enter了但是沒有Leave則下一個線程獲取不了信號,下一個線程得不到執(zhí)行 /* #include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1( LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; CRITICAL_SECTION section; int main() { HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL); HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); InitializeCriticalSection(§ion); Sleep(4000); DeleteCriticalSection(§ion); return 0; } DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ) { while(TRUE) { EnterCriticalSection(§ion); if(tickes>0) { cout$amp;
//死鎖的體現(xiàn) /*#include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1 LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; CRITICAL_SECTION sectionA; CRITICAL_SECTION sectionB; int main() { HANDLE hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL); HANDLE hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,NULL); CloseHandle(hThread1); CloseHandle(hThread2); InitializeCriticalSection(§ionA); InitializeCriticalSection(§ionB); Sleep(4000); DeleteCriticalSection(§ionB); DeleteCriticalSection(§ionA); return 0; } DWORD WINAPI ThreadProc1( LPVOID lpParameter // thread data ) { while(TRUE) { EnterCriticalSection(§ionA); Sleep(1); EnterCriticalSection(§ionB); if(tickes>0) { cout$amp;