`
xitonga
  • 浏览: 588089 次
文章分类
社区版块
存档分类
最新评论

线程同步与异步套接字编程

 
阅读更多
线程同步与异步套接字编程

1.事件对象
上一次介绍了利用互斥对象实现线程同步http://blog.csdn.net/walkerkalr/article/details/19510909。这次将继续介绍另两种线程同步的方法:事件对象和关键字代码段。
1.1事件对象
事件对象也属于内核对象,包括三个成员
1)使用计数
2)用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值
3)用于指明该事件处于已通知状态还是未通知状态的布尔值

事件对象有两种不同的类型:人工重置的事件对象和自动重置的事件对象。当人工重置的事件对象得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件对象得到通知时,等待该时间对象的线程只有一个线程变为可调度线程。

1.2创建事件对象
1.2.1相关函数:
HANDLE CreateEvent( //创建事件对象
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPTSTR lpName);

BOOL SetEvent(//设置事件对象状态
HANDLE hEvent );

BOOL ResetEvent( //重置事件对象状态
HANDLE hEvent );

1.2.1利用事件对象实现线程同步
#include <windows.h>
#include <iostream>


using namespace std;


DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);


DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);


int tickets=100;
HANDLE g_hEvent;


void main()
{
	HANDLE hThread1;
	HANDLE hThread2;
	hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
	hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);


	g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");
	if(g_hEvent)
	{
		if(ERROR_ALREADY_EXISTS==GetLastError())
		{
			cout<<"only instance can run!"<<endl;
			return;
		}
	}


	Sleep(4000);
	CloseHandle(g_hEvent);
}


DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
	while(TRUE)
	{
		WaitForSingleObject(g_hEvent,INFINITE);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread1 sell ticket : "<<tickets--<<endl;
		}
		else
			break;
		SetEvent(g_hEvent);
	}
	
	return 0;
}


DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
	
	while(TRUE)
	{
		WaitForSingleObject(g_hEvent,INFINITE);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread2 sell ticket : "<<tickets--<<endl;
		}
		else
			break;
		SetEvent(g_hEvent);
	}
	
	return 0;
}

为了实现线程间的同步不应该使用人工重置的事件对象,而应该使用自动重置的事件对象。
当人工重置的事件对象得到通知时,等待该事件对象的所有线程均变为可调度线程;当一个自动重置的事件对象得到通知时,等待该事件对象的线程中只有一个线程变为可调度线程,同时操作系统会将该事件设置无信号状态,这样,当对所保护的代码执行完成后,需要调用SetEvent函数将该事件对象设置为有信号状态。而人工重置的事件对象,在一个线程得到该事件对象之后,操作系统并不会将该事件对象设置为无信号状态,除非显式的调用ResetEvent函数将其设置为无信号状态,否则该对象会一直是有信号状态。

2.关键代码段(临界区)
关键代码段也成为临界区,工作在用户方式下,它是指一个小代码段,在代码能够执行前,他必须独占对某些资源的访问权。
2.1相关API函数
void InitializeCriticalSection(//初始化临界区
LPCRITICAL_SECTION lpCriticalSection );

void EnterCriticalSection( //进入临界区
LPCRITICAL_SECTION lpCriticalSection );

void LeaveCriticalSection( //离开临界区
LPCRITICAL_SECTION lpCriticalSection );

void DeleteCriticalSection( //销毁临界区
LPCRITICAL_SECTION lpCriticalSection );

2.2利用临界区实现线程同步
#include <windows.h>
#include <iostream>


using namespace std;


DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
);


DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
);


int tickets=100;


CRITICAL_SECTION g_cs;


void main()
{
	HANDLE hThread1;
	HANDLE hThread2;
	hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
	hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
	CloseHandle(hThread1);
	CloseHandle(hThread2);


	InitializeCriticalSection(&g_cs);
	Sleep(4000);


	DeleteCriticalSection(&g_cs);
}


DWORD WINAPI Fun1Proc(
  LPVOID lpParameter   // thread data
)
{
	while(TRUE)
	{
		EnterCriticalSection(&g_cs);
		Sleep(1);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread1 sell ticket : "<<tickets--<<endl;
			LeaveCriticalSection(&g_cs);
		}
		else{
			LeaveCriticalSection(&g_cs);
			break;
		}
	}
	
	return 0;
}


DWORD WINAPI Fun2Proc(
  LPVOID lpParameter   // thread data
)
{
	
	while(TRUE)
	{
		EnterCriticalSection(&g_cs);
		Sleep(1);
		if(tickets>0)
		{
			Sleep(1);
			cout<<"thread2 sell ticket : "<<tickets--<<endl;
			LeaveCriticalSection(&g_cs);
		}
		else{
			LeaveCriticalSection(&g_cs);
			break;
		}
	}
	return 0;
}

3.线程死锁
对多线程来说,如果线程1拥有临界区对象A,等待临界区对象B的拥有权,线程2拥有临界区对象B,等待临界区对象A的拥有权,这就造成了死锁。

4.互斥对象、时间对象和关键代码段的比较
区别:
1)互斥对象和时间对象都属于内核对象,利用内核对象进行线程同步时,速度慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。
2)关键代码段工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为等待进入关键代码段时无法设定超时值。

5.基于消息的异步套接字
windows套接字在两种模式下执行I/O操作:阻塞模式和非阻塞模式。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会理解返回;在非阻塞模式下,Winsock函数无论如何都会立即返回,在该函数执行的操作完成之后,系统会采用某种方式将操作结果通知给调用线程,后者根据通知信息可以判断该操作使正常完成了,还是出现错误了。

相关函数说明:
int WSAAsyncSelect(//选择网络事件通知windows消息
SOCKET s,
HWND hWnd,
unsigned int wMsg,
long lEvent
);

int WSAEnumProtocols(//获取网络协议相关信息
LPINT lpiProtocols,
LPWSAPROTOCOL_INFO lpProtocolBuffer,
ILPDWORD lpdwBufferLength
);

int WSAStartup(//初始化WS2_32.DLL的使用
WORD wVersionRequested,
LPWSADATA lpWSAData
);

int WSACleanup (void);//终止WS2_32.DLL使用

SOCKET WSASocket(//创建套接字
int af,
int type,
int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo,
GROUP g,
DWORD dwFlags
);

int WSARecvFrom(//接受消息
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,
LPDWORD lpFlags,
struct sockaddr FAR *lpFrom,
LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

int WSASendTo(//发送消息
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR *lpTo,
int iToLen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

struct hostent FAR *gethostbyname(//根据主机名获取IP
const char FAR *name
);

struct HOSTENT FAR * gethostbyaddr(//根据IP获取主机名
const char FAR *addr,
int len,
int type

);


==参考VC++深入详解

==转载请注明出处,谢谢!

分享到:
评论

相关推荐

    vc++ 线程同步与异步套接字编程实例

    vc++ 线程同步与异步套接字编程实例,Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。而在非...

    Lesson16线程同步与异步套接字编程

    线程同步与异步套接字编程 线程同步与异步套接字编程

    visual c++ MFC之Lesson16线程同步与异步套接字编程

    visual c++ MFC之Lesson16线程同步与异步套接字编程

    C++的线程同步与异步套接字编程源码.zip

    C++的线程同步与异步套接字编程源码.zip

    VC++ 线程同步与异步套接字编程实例

    摘要:VC/C++源码,系统相关,线程同步,套接字编程 VC++线程同步与异步套接字编程实例源码,

    线程同步与异步套接字VC++编程实例

    摘要:VC/C++源码,系统相关,线程同步,套接字 线程同步与异步套接字VC++编程实例,演示如何保证应用程序只有一个进程、线程死锁、基于消息的异步套接字实现,若要更细节的了解,请下载源码编译运行。

    c#异步/同步多线程套接字

    c#异步/同步多线程套接字,包里有两个项目文件(客户端和服务器端)。 项目源码采用vs2013编程,使用的是winform方式编码,源码有详细注释。15年底是用于给客户演示用,现在拿出来给大家分享。

    孙鑫C++教程(全20讲)PPT讲义源码及电子书

    最近正在学习C++,费了很多心思...第十六课:线程同步与异步套接字编程 第十七课:进程间通信 第十八课:ActiveX控件 第十九课:动态链接库 第二十课:HOOK和数据库访问 希望对大家的学习有帮助,如果不错,请帮点个赞,谢谢

    C#.net同步异步SOCKET通讯和多线程总结

    同步套接字通信 Socket支持下的网上点对点的通信 Socket编程原理 基于TCP协议的发送和接收端 异步套接字 多线程

    VC.MFC套接字socket网络编程,完整代码高速文件传输,多线程,可直接生成使用,VS2010

    采用VS2010,基于MFC实现大文件高速传输,socket同步异步灵活切换使用,多进程。完整项目,可直接生成使用。非常适合初学者和有一定基础的提高者。自定义对话框工具,设计完美,界面美观。学习交流,拒绝商用。宸宸...

    vc深入详解

    VC++深入详解学习笔记 1 Lesson1: Windows程序运行原理及程序编写流程 1 ...Lesson 16 线程同步与异步套接字 50 Lesson17进程间通信 59 Lesson18 Active控件 67 Lesson19 动态链接库DLL 70 Lesson20 Hook与数据编程 75

    C#网络应用高级编程

    1.3 套接字  1.3.1 Socket类  1.3.2 面向连接的套接字  1.3.3 无连接的套接字  1.4 网络流  习题  第2章 TCP应用编程  2.1 同步TCP应用编程  2.1.1 使用套接字发送和接收数据  2.1.2 ...

    socketjava源码-demo-sockets-io-nio-nio2:“Java套接字I/O:阻塞,非阻塞和异步”文章和源代码

    本文描述了Java中非阻塞和异步套接字I / O操作之间的理论和实践差异。 套接字是通过TCP和UDP协议执行双向通信的端点。 Java套接字API是用于操作系统相应功能的适配器。 符合POSIX的操作系统(Unix,Linux,Mac OS X...

    MFC网络编程之自制浏览器

    网络编程,当然要用到Windows Socket(套接字)技术。Socket相关的操作由一系列API函数来完成,比如socket、bind、listen、connect、accept、send、sendto、recv、recvfrom等。调用这些API函数有一定的先后次序,有些...

    《Windows网络编程技术》高清PDF版+随书源码

    直接网络编程5.1 原始套接字编程5.1.1 原始套接字简介5.1.2 WinSock的原始套接字5.1.3 Winsock原始套接字编程步骤5.1.4 Winsock原始套接字实例5.2 基于winPcap网络数据包捕获5.2.1 WinPcap简介5.2.2 网络数据包捕获...

    VC++经典PPT (入门与提高)大全

    这是一套学习VC++,MFC的一到经典的学习PPT 从基础入手,逐渐提高,内容解释详细,是套很不错的学习资料,内容包括,Windows程序运行原理,掌握c++,文本编程...线程同步与异步套接字,网络编程,文件,HOOK和数据库访问

    .Net Socket编程资料

    (6)同步套接字通信;(7)续实例解析SOCKET编程模型之异步通;(8)在C#中使用异步Socket编程实现TCP网络服务的CS的通讯构架;(9)重新研究socket传输自定义对象 9个doc帮助文档,已经两个Demo程序.请下载学习

    WINDOWS网络编程技术.pdf

    直接网络编程5.1 原始套接字编程5.1.1 原始套接字简介5.1.2 WinSock的原始套接字5.1.3 Winsock原始套接字编程步骤5.1.4 Winsock原始套接字实例5.2 基于winPcap网络数据包捕获5.2.1 WinPcap简介5.2.2 网络数据包捕获...

    C#网络核心编程(Word版电子书+PPT+源代码+习题解答)

    1.3.2 面向连接的套接字 21 1.3.3 无连接的套接字 23 1.4 网络流 24 1.5 习题1 25 第2章 TCP应用编程 27 2.1 同步TCP应用编程 28 2.1.1 使用套接字发送和接收数据 28 2.1.2 使用NetworkStream对象发送和接收数据 30 ...

Global site tag (gtag.js) - Google Analytics