第十六章 线程同步与异步套接字编程
来源:互联网 发布:汽车工业的重要性 知乎 编辑:程序博客网 时间:2024/05/18 16:19
事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。
有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。
当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。
我们一般不使用人工重置事件对象;
内核对象(包含):事件对象、互斥对象、
API函数HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
创建事件同步对象
非信号状态,则阻塞WaitForSingleObject(g_hEvent,INFINITE)所保护的程序代码;WaitForSingleObject(g_hEvent,INFINITE)函数就是等待同步对象的信号状态的到来;
同步对象为“非信号”状态时,将阻塞WaitForSingleObject()保护的代码。
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(
);
DWORD WINAPI Fun2Proc(
);
int tickets=100;
HANDLE g_hEvent;
void main()
{
}
DWORD WINAPI Fun1Proc(
{
//
}
DWORD WINAPI Fun2Proc(
)
{
}
-----------------------------------------------------------------------------------------------
关键代码段(也称临界区)与死锁
关键代码段(临界区)是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。
函数void InitializeCriticalSectio
函数void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection )判断临界区对象是否被占有,如果被占有,则阻塞(即不执行,在一直此等,直至....);如果没被占有,则占有之,并继续往下执行;
如果不再需要占有临界区对象,则使用void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)函数,释放之;
函数void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)释放与指定的没有被占有的临界区对象相关的所有资源;
线程1拥有了临界区对象A,等待临界区对象B的拥有权,线程2拥有了临界区对象B,等待临界区对象A的拥有权,就造成了死锁。
调用函数Sleep(),则意味着它所在的线程放弃了CPU执行时间;
互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。
关键代码段(即临界区对象)是工作在用户方式下,同步速度较快,但在使用关键代码段时,但很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。
在MFC应程中使用关键代码段,一般是在类的构造函数中使用InitializeCriticalSectio
#include <windows.h>
#include <iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
void main()
{
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
}
-------------------------------------------------------------------------------------------------
基于消息的异步套接字
本应程和上一节的多线程应程不一样,此处是单线程、对网络事件采取基于消息的异步存取策略。
(在同一个线程中,某部分代码只需将字符串送出即可,不必管其他细节,当消息确实已送出且到达目的地,则系统会为字符串到达这个事件(当然必须事先已经注册了)触发一个消息,然后我们可以在该消息相应函数中接收字符串,并作相应处理。)
(如果在同一个线程中,我们仍使用阻塞机制,如果在发送数据之前,程序先执行的是接受数据的语句,则程序会一直等下去,造成阻塞。这是不希望看到的)
前几节课,我们的套接字是工作在阻塞模式下(也即同步模式),因此其执行效率较低;
函数int WSAAsyncSelect(SOCKET s,
可以这样理解:SOCKET m_socket; 定义的套接字是阻塞模式,当调用WSAAsyncSelect()函数注册一个网络事件,也就将相应的套接字(即该函数的一个参数)设置为非阻塞模式。
int WSAEnumProtocols(LPINT lpiProtocols,
Win32平台支持多种不同的网络协议,采用Winsock2,就可以编写可直接使用任何一种协议的网络应用程序了。通过WSAEnumProtocols函数可以获得系统中安装的网络协议的相关信息。
lpiProtocols,一个以NULL结尾的协议标识号数组。这个参数是可选的,如果lpiProtocols为NULL,则返回所有可用协议的信息,否则,只返回数组中列出的协议信息。
lpProtocolBuffer,[out],一个用WSAPROTOCOL_INFO结构体填充的缓冲区。 WSAPROTOCOL_INFO结构体用来存放或得到一个指定协议的完整信息。
lpdwBufferLength,[in, out],在输入时,指定传递给WSAEnumProtocols()函数的lpProtocolBuffer缓冲区的长度;在输出时,存有获取所有请求信息需传递给WSAEnumProtocols ()函数的最小缓冲区长度。这个函数不能重复调用,传入的缓冲区必须足够大以便能存放所有的元素。这个规定降低了该函数的复杂度,并且由于一个 机器上装载的协议数目往往是很少的,所以并不会产生问题。
SOCKET类型,其是就是 无符号整形。
语句分析:
在对话框类的析构函数中:
以前我们创建套节字是在定义的同时创建的,即通过构造函数创建的;这里,我们使用windows的扩展函数来创建。
函数SOCKET WSASocket( int af,
SOCKET WSASocket( int af, int type, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags );
前三个参数和socket()函数的前三个参数含义一样。
lpProtocolInfo,一个指向WSAPROTOCOL_INFO结构体的指针,该结构定义了所创建的套接字的特性。如果lpProtocolInfo为NULL,则WinSock2 DLL使用前三个参数来决定使用哪一个服务提供者,它选择能够支持规定的地址族、套接字类型和协议值的第一个传输提供者。如果lpProtocolInfo不为NULL,则套接字绑定到与指定的结构WSAPROTOCOL_INFO相关的提供者。
g,保留的。
dwFlags,套接字属性的描述。
绑定没有提供扩展函数,仍是用bind();
int WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR *lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
s,标识套接字的描述符。
lpBuffers,[in, out],一个指向WSABUF结构体的指针。每一个WSABUF结构体包含一个缓冲区的指针和缓冲区的长度。
dwBufferCount, lpBuffers数组中WSABUF结构体的数目。
lpNumberOfBytesRecvd,[out],如果接收操作立即完成,则为一个指向本次调用所接收的字节数的指针。
lpFlags,[in, out],一个指向标志位的指针。
lpFrom,[out],可选指针,指向重叠操作完成后存放源地址的缓冲区。
lpFromlen,[in, out],指向from缓冲区大小的指针,仅当指定了lpFrom才需要。
lpOverlapped,一个指向WSAOVERLAPPED结构体的指针(对于非重叠套接字则忽略)。
lpCompletionRoutine,一个指向接收操作完成时调用的完成例程的指针(对于非重叠套接字则忽略)。
s,标识一个套接字(可能已连接)的描述符。
lpBuffers,一个指向WSABUF结构体的指针。每一个WSABUF结构体包含一个缓冲区的指针和缓冲区的长度。
dwBufferCount, lpBuffers数组中WSABUF结构体的数目。
lpNumberOfBytesSent,[out],如果发送操作立即完成,则为一个指向本次调用所发送的字节数的指针。
dwFlags,指示影响操作行为的标志位。
lpTo,可选指针,指向目标套接字的地址。
iToLen,lpTo中地址的长度。
lpOverlapped,一个指向WSAOVERLAPPED结构的指针(对于非重叠套接字则忽略)。
lpCompletionRoutine,一个指向接收操作完成时调用的完成例程的指针(对于非重叠套接字则忽略)。
BOOL CChatApp::InitInstance()
{
}
BOOL CChatDlg::InitSocket()
{
}
BEGIN_MESSAGE_MAP(CChatDlg, CDialog)
END_MESSAGE_MAP()
void CChatDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
}
void CChatDlg::OnBtnSend()
{
}
终止套接字库的使用
CChatApp::~CChatApp()
{
}
CChatDlg::~CChatDlg()
{
}
本文出处:http://blog.sina.com.cn/s/blog_690e57390100l3ol.html
- 第十六章 线程同步与异步套接字编程
- 《VC++深入详解》学习笔记 第十六章 线程同步与异步套接字编程
- 孙鑫: 第十六讲 线程同步与异步套接字编程收
- 线程同步与异步套接字编程
- 线程同步与异步套接字编程
- 线程同步与异步套接字编程
- 线程同步与异步套接字编程
- 线程同步与异步套接字编程小结
- (孙鑫 十六) 线程同步与异步套接字编程
- 第16课 线程同步与异步 套接字编程
- MFC(线程同步与异步套接字,孙鑫C++第十六讲笔记整理)
- MFC - 线程同步与异步套接字 (孙鑫C++第十六讲笔记整理)
- 线程同步与异步套接字
- 孙鑫VC++第16章线程同步与异步套接字编程
- 《VC++深入详解》学习笔记[13]——第16章 线程同步与异步套接字编程
- 孙鑫教学视频笔记 (16)线程同步与异步套接字编程
- 学习笔记:第16课:线程同步与异步套接字编程
- 孙鑫教学视频笔记 (16)线程同步与异步套接字编程
- java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanCre
- sdut 2609 A-Number and B-Number
- Python Tricks(十二)—— 有理数的加法
- android studio没有创建Android项目的选项,打开已有android studio项目无法运行的问题
- unicode字符和多字节字符的相互转换接口
- 第十六章 线程同步与异步套接字编程
- springMVC Freemarker 取map值
- Android减少内存泄漏之静态内部类的使用
- SQL优化----百万数据查询优化
- 翻译:HTML5与HTML4的区别
- 蓝桥杯--2N皇后
- std::string 跨进程可能崩溃
- Overloading(小结)
- socket套接字选项列表