关闭

锁定模式下的非锁定实现

859人阅读 评论(0) 收藏 举报

锁定模式下的非锁定实现

Lanno Ckeeke  2006060701

说明

锁定模式下为了避免socket在进行IO操作时一直处于“凝固”状态,简单地用两个线程来实现:一个线程用于数据的接收;另一个线程则用于对接收到的数据进行相关的处理。因为由两个线程来实现,其特点:

     对数据的处理可以是耗时操作,它不会对数据的接收带来影响。

     对数据的接收与处理分别在不同的线程内,故应考虑数据的完整性,应避免在数据接收完全之前就对数据进行操作,可以以多种方式实现:如Mutex,Semphore,CriticalSection等同步技术。

     当数据接收完全之后,还需要及时的通知另一个线程,以便及时处理。其实现方法是:当接收完数据后,发送已完成信号。

详细说明参见<Windows网络编程>一书。

本代码中应用CriticalSectionevent来实现。

需要注意的是:event为自动重置

完整代码及注释

  1. // zBlogSocket.cpp : 定义控制台应用程序的入口点。
  2. //
  3. //多线程socket锁定
  4.  
  5. #include "stdafx.h"
  6. #include <WinSock2.h>
  7. #include <Windows.h>
  8. #include <iostream>
  9. using namespace std;
  10.  
  11. CRITICAL_SECTION cs;
  12. HANDLE hComplete;
  13. TCHAR buf[BUFSIZ];
  14. int nBytes;
  15. //number of per receive
  16. const int nNumPerRecv = BUFSIZ;
  17.  
  18. //从socket接收数据线程
  19. DWORD WINAPI ReadThread(LPVOID lpParam);
  20. //对接受到的数据进行计算的线程
  21. DWORD WINAPI ComptThread(LPVOID lpParam);
  22.  
  23. int _tmain(int argc, _TCHAR* argv[])
  24. {
  25.      WSAData wsd;
  26.      int nRet = WSAStartup(0x0202,&wsd);
  27.      if (nRet != 0) {
  28.           cout << "WSAStartup Error = " << WSAGetLastError() << endl;
  29.          return 1;
  30.      }
  31.  
  32.      SOCKET soRecv = socket(AF_INET,SOCK_STREAM,0);
  33.      SOCKADDR_IN siRecv;
  34.      siRecv.sin_addr.s_addr = inet_addr("127.0.0.1");
  35.      siRecv.sin_family = AF_INET;
  36.      siRecv.sin_port = htons(5150);
  37.  
  38.      nRet = bind(soRecv,(struct sockaddr*)&siRecv,sizeof(siRecv));
  39.      if (nRet == SOCKET_ERROR) {
  40.          cout << "bind Error = " << WSAGetLastError() << endl;
  41.          return 1;
  42.      }
  43.  
  44.      listen(soRecv,8);
  45.  
  46.  
  47.      HANDLE hThreads[2];
  48.      DWORD dwThread[2];
  49.  
  50.      //初始化cs
  51.      InitializeCriticalSection(&cs);
  52.  
  53.      hThreads[0] = CreateThread(NULL,0,ReadThread,(LPVOID)soRecv,0,&dwThread[0]);
  54.      hThreads[1] = CreateThread(NULL,0,ComptThread,NULL,0,&dwThread[1]);
  55.     
  56.      //创建自动重置的event对象,当ReadThread接收数据完毕
  57.      //后将信号置为signaled
  58.      hComplete = CreateEvent(NULL,false,FALSE,"evt");
  59.     
  60.      //等待创建的两个线程结束
  61.      WaitForMultipleObjects(2,hThreads,true,INFINITE);
  62.  
  63.      //清除cs
  64.      DeleteCriticalSection(&cs);
  65.  
  66.      return 0;
  67. }
  68.  
  69. //从socket接收数据线程
  70. DWORD WINAPI ReadThread(LPVOID lpParam){
  71.      int nTotal = 0;
  72.      int nRead = 0;
  73.      int nLeft = 0;
  74.      int nReadBytes = 0;
  75.      int nBytes = 0;
  76.      SOCKET pSoRecv = (SOCKET)lpParam;
  77.      int dwSend;
  78.      SOCKADDR_IN siSend;
  79.      SOCKET soAccept;
  80.  
  81.  
  82.      while (1) {
  83.  
  84.          nTotal = 0;
  85.          nLeft = nNumPerRecv;
  86.  
  87.          /*   10014错误原因
  88.          *    int dwSend = sizeof(dwSend);
  89.               Error = 10014
  90.          */
  91.          int dwSend = sizeof(siSend);
  92.          soAccept = accept(pSoRecv,(struct sockaddr*)&siSend,&dwSend);
  93.          if (soAccept == SOCKET_ERROR) {
  94.               cout << "accept Error = " << WSAGetLastError() << endl;
  95.               system("pause");
  96.  
  97.          }
  98.  
  99.  
  100.          //接收到的数据为空
  101.          nBytes = 0;
  102.          memset(buf,0,BUFSIZ);
  103.          while (nTotal != nNumPerRecv) {
  104.               //同步操作进入cs
  105.               EnterCriticalSection(&cs);
  106.               /*
  107.                *   Recv data from socket and place data in buf[nBytes]
  108.                */
  109.               //nRead = recv(soAccept,&buf[BUFSIZ - nBytes],nLeft,0);
  110.               nRead = recv(soAccept,&buf[nBytes],nLeft,0);
  111.               if (nRead == -1) {
  112.                    cout << "recv error = " << WSAGetLastError() << endl;
  113.                    ExitThread(1);
  114.               }
  115.               nTotal += nRead;
  116.               nLeft -= nRead;
  117.               nBytes += nRead;
  118.               //离开cs
  119.               LeaveCriticalSection(&cs);
  120.  
  121.          }
  122.          //激发event
  123.          SetEvent(hComplete);
  124.      }
  125. }
  126. //对接受到的数据进行计算的线程
  127. DWORD WINAPI ComptThread(LPVOID lpParam){
  128.      //等待ReadThread将数据接受完成后再进行计算
  129.      while (1) {
  130.          WaitForSingleObject(hComplete,INFINITE);
  131.  
  132.          //对全局变量操作进入cs
  133.          EnterCriticalSection(&cs);
  134.          cout << buf << endl;
  135.          nBytes -= nNumPerRecv;
  136.          //离开cs
  137.          LeaveCriticalSection(&cs);
  138.      }
  139.  
  140.      return 0;
  141.  
  142. }

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:144298次
    • 积分:2060
    • 等级:
    • 排名:第19309名
    • 原创:62篇
    • 转载:4篇
    • 译文:1篇
    • 评论:9条
    文章分类
    最新评论
    标准与权威