读书人

MFC(线程同步与异步套接字,孙鑫C++第十

发布时间: 2012-09-14 11:53:44 作者: rapoo

MFC(线程同步与异步套接字,孙鑫C++第十六讲笔记整理)

1.事件对象:来实现线程的同步。与互斥对象一样均属于内核对象。

当人工重置有信号时,所有线程均得到信号,所以不能设为人工重置。代码就不贴了,通过创建匿名的事件对象,也可以让一个程序只能运行一个实例。

2.关键代码段实现线程的同步:类似公用电话亭,只有当电话亭里面没人了,其它人才可以再进去打电话。用了4个函数,这种方法比较简单!但缺点是如果使用了多少关键代码码,容易赞成线程的死锁

3.线程死锁,用关键代码示例,用了两个临界区对象,实战中要注意避免这种错误!

4.使用异步套接字编写网络聊天室

1)加载套接字库,进行版本协商,包含头文件,链接库文件,这次请示的是2.2版本!

2)在类CChatDlg中增加一个成员变量m_socket,在析构函数中释放这个变量

3)利用WSASocket()创建套接字(数据报类型的UDP型的)

4)然后调用WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ)为网络事件定义消息!此时如果发生FD_READ消息,系统会发送UM_SOCK消息给应用程序!程序并不会阻塞在这儿了!

以上是在BOOL CChatDlg::OnInitDialog()完成

5)然后完成消息响应!

头文件中:#define UM_SOCK WM_USER+1

afx_msg void OnSock(WPARAM,LPARAM);

源文件中:

ON_MESSAGE(UM_SOCK,OnSock)

实现消息响应函数: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("接收数据失败!");

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)完成数据发送的功能!

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("发送数据失败!");

return;

}

} 7)完成将主机名转换为IP地址的功能,以前将IP地址转换为主机名的功能,单线程的聊天室创建完毕!性能并且非常出色!

下面是一些具体的代码:

#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<<"thread1 sell ticke: "<<tickes--<<endl;}else{break;}//ReleaseMutex(hEvent);ResetEvent(hEvent);}return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter   // thread data ){while(TRUE){SetEvent(hEvent);WaitForSingleObject(hEvent,INFINITE);if(tickes>0){cout<<"thread2 sell ticke: "<<tickes--<<endl;}else{break;}//ReleaseMutex(hEvent);ResetEvent(hEvent);}return 0;}


//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<<"thread1 sell ticke: "<<tickes--<<endl;}else{break;}}return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter   // thread data ){while(TRUE){WaitForSingleObject(hEvent,INFINITE);if(tickes>0){cout<<"thread2 sell ticke: "<<tickes--<<endl;}else{break;}}return 0;}*///结论是,设置自动的,并且开始有信号(无信号可以调用SetEvent来使无信号到有信号的一个转变)//只有一个线程获得了信号,并且运行完后(时间片到了),则下一个线程是无法运行的,因为此时只有一个//线程有信号,并且运行完后,马上使得事件对象无信号


//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<<"thread1 sell ticke: "<<tickes--<<endl;}else{break;}}return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter   // thread data ){while(TRUE){WaitForSingleObject(hEvent,INFINITE);if(tickes>0){cout<<"thread2 sell ticke: "<<tickes--<<endl;}else{break;}}return 0;}*///使用手动设置,则任何线程都获得了信号,都可以运行,可以使用ResetEvent使得信号变得无效


//关键代码段,临界区域//如果只是Enter了但是没有Leave则下一个线程获取不了信号,下一个线程得不到执行/*#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<<"thread1 sell ticke: "<<tickes--<<endl;}else{break;}LeaveCriticalSection(§ion);}return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter   // thread data ){while(TRUE){EnterCriticalSection(§ion);if(tickes>0){cout<<"thread2 sell ticke: "<<tickes--<<endl;}else{break;}LeaveCriticalSection(§ion);}return 0;}*/


//死锁的体现/*#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<<"thread1 sell ticke: "<<tickes--<<endl;}else{break;}LeaveCriticalSection(§ionB);LeaveCriticalSection(§ionA);}return 0;}DWORD WINAPI ThreadProc2( LPVOID lpParameter   // thread data ){while(TRUE){EnterCriticalSection(§ionB);Sleep(1);EnterCriticalSection(§ionA);if(tickes>0){cout<<"thread2 sell ticke: "<<tickes--<<endl;}else{break;}LeaveCriticalSection(§ionA);LeaveCriticalSection(§ionB);}return 0;}*/


MFC(线程同步与异步套接字,孙鑫C++第十六讲札记整理)

MFC(线程同步与异步套接字,孙鑫C++第十六讲札记整理)

读书人网 >C++

热点推荐