锁定模式下的非锁定实现

原创 2006年06月07日 22:38:00

锁定模式下的非锁定实现

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. }

 

相关文章推荐

单例模式中的 双重检查锁定(Double-Check Locking )

先上代码:Singleton类 namespace Singleton { public class Singleton { //定义一个私有的静态全局变...
  • daman7
  • daman7
  • 2011年11月21日 14:05
  • 1054

【C#】C#中单例的双重锁定模式

using System; using System.Collections.Generic; /// /// 适用于在多线程的情况下保证只有一个实例化对象的情况,例如银行的操作系统 /// na...

【设计模式】深入理解单例&懒汉饿汉&双重锁定

在实际的开发中,我们需要某个类只有唯一一个实例,比如在Windows中我们打开任务管理器,即使点击多次,每次也只是有一个窗口。我们一起看下单例模式的定义:        单例模式(Singleton ...

双重检查锁定模式(DCL)

双重检查锁定模式[编辑] 双重检查锁定模式(也被称为"双重检查加锁优化","锁暗示"(Lock hint)[1]) 是一种软件设计模式用来减少并发系统中竞争和同步的开销。双重...

单例模式、双检测锁定DCL、volatile

单例模式最要关心的则是对象创建的次数以及何时被创建。 Singleton模式可以是很简单的,它的全部只需要一个类就可以完成(看看这章可怜的UML图)。但是如果在“对象创建的次数以及何时被创建”这两点上...

双重检查锁定及单例模式

编辑注:本文在针对 Java 5.0 修订前参考了 Java 内存模型;关于内存排序的描述也许不再正确。尽管如此,在新的内存模型中,双重检查锁定习语仍旧是无效的。 单例创建模式是一个通用的编程习...

C++和双重检查锁定模式(DCLP)的风险

转自: http://blog.jobbole.com/86392/ 多线程其实就是指两个任务一前一后或者同时发生。 1 简介 当你在网上搜索设计模式的相关资料时,你一定会找到最常被提及的一个模式...

Java设计模式之单例与双重锁定

在java设计模式之中,单例算是比较常用的了~本文章就是简单介绍单例的用法...

java 双重检查锁定及单例模式

双重检查锁定及单例模式全面理解这一失效的编程习语Peter Haggar , 高级软件工程师, IBMPeter Haggar 是 IBM 在北卡罗来纳州的 Research Triangle Pa...
  • kufeiyun
  • kufeiyun
  • 2011年01月27日 15:09
  • 15562

双重检查锁定(double-checked locking)与单例模式

单例模式有如下实现方式:package com.zzj.pattern.singleton; public class Singleton { private static Singleton i...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:锁定模式下的非锁定实现
举报原因:
原因补充:

(最多只允许输入30个字)