分享

MFC(线程同步与异步套接字,孙鑫

 禁忌石 2017-05-05

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

提问者: yaozhi3333     发布时间:2014-06-26     浏览:66     回复:0     悬赏:0.0希赛币
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_SOCKWM_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$amp;<><><><="" p="" style="margin: 0px; padding: 0px; list-style: none;">

  //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;<><><><="" p="" style="margin: 0px; padding: 0px; list-style: none;">

  //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;<><><><="" p="" style="margin: 0px; padding: 0px; list-style: none;">

  //关键代码段,临界区域 //如果只是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$amp;<><><><="" p="" style="margin: 0px; padding: 0px; list-style: none;">

  //死锁的体现 /*#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;<><><><="" p="" style="margin: 0px; padding: 0px; list-style: none;">

  890x671

  890x664


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多