孙鑫16课线程同步与异步套接字编程Word格式.docx

上传人:b****4 文档编号:18406748 上传时间:2022-12-16 格式:DOCX 页数:14 大小:19.20KB
下载 相关 举报
孙鑫16课线程同步与异步套接字编程Word格式.docx_第1页
第1页 / 共14页
孙鑫16课线程同步与异步套接字编程Word格式.docx_第2页
第2页 / 共14页
孙鑫16课线程同步与异步套接字编程Word格式.docx_第3页
第3页 / 共14页
孙鑫16课线程同步与异步套接字编程Word格式.docx_第4页
第4页 / 共14页
孙鑫16课线程同步与异步套接字编程Word格式.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

孙鑫16课线程同步与异步套接字编程Word格式.docx

《孙鑫16课线程同步与异步套接字编程Word格式.docx》由会员分享,可在线阅读,更多相关《孙鑫16课线程同步与异步套接字编程Word格式.docx(14页珍藏版)》请在冰豆网上搜索。

孙鑫16课线程同步与异步套接字编程Word格式.docx

//g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);

g_hEvent=CreateEvent(NULL,FALSE,FALSE,"

tickets"

//自动重置,初始无信号。

if(g_hEvent)

{

if(ERROR_ALREADY_EXISTS==GetLastError())

{

cout<

<

"

onlyinstancecanrun!

endl;

return;

}

}

SetEvent(g_hEvent);

Sleep(4000);

CloseHandle(g_hEvent);

}

while(TRUE)

WaitForSingleObject(g_hEvent,INFINITE);

//ResetEvent(g_hEvent);

if(tickets>

0)

Sleep

(1);

thread1sellticket:

"

tickets--<

else

break;

SetEvent(g_hEvent);

return0;

thread2sellticket:

下面创建另一个线程同步的方式:

关键代码段:

关键代码段(临界区)工作在用户方式下。

关键代码段(临界区)是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。

可以把访问同一种资源的代码看成是关键代码段。

新建一个WIN32的控制台程序:

LPVOIDlpParameter//threaddata

);

CRITICAL_SECTIONCriticalSection;

InitializeCriticalSection(&

CriticalSection);

DeleteCriticalSection(&

EnterCriticalSection(&

//在要保护的资源代码前加上这句,

//在访问后释放临界区对象所有权。

如果得不到对临界资源的访问权,则线程等待下去。

//线程1执行完成之后,线程1退出,但是如果线程1没有释放临界区对象的所有权,则线程2一直等待临界区对象的使用权,

//则线程2无法得到临界区对象的使用权,线程2一直等,直到主线程退出。

进程退出,线程2也退出。

LeaveCriticalSection(&

在使用临界区对象的时候,要注意释放临界区对象的所有权。

要注意死锁的问题。

死锁问题:

线程1拥有了临界区对象A,等待临界区对象B的拥有权,线程2拥有了临界区对象B,等待临界区对象A的拥有权,就造成了死锁。

死锁代码如下:

CRITICAL_SECTIONg_csA;

CRITICAL_SECTIONg_csB;

g_csA);

g_csB);

Sleep

(1);

//释放的顺序无所谓

cout<

thread2isrunning!

三种实现线程同步的方式的比较:

互斥对象、事件对象与关键代码段的比较

⏹互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。

⏹关键代码段是工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。

推荐书目

《Windows核心编程》机械工业出版社

在实现线程同步时,首选关键代码段。

若在MFC程序中,可以在一个类的构造函数中调用InitializeCriticalSection();

在析构函数中调用DeleteCriticalSection()。

在要保护的代码前面加上EnterCriticalSection();

在访问完要保护的资源后调用LeaveCriticalSection();

记得一定要释放关键代码段。

如果构造了多个临界区对象,要注意线程死锁。

多个进程的各个线程间,要用互斥对象和事件对象。

基于消息的异步套接字编程:

⏹Windows套接字在两种模式下执行I/O操作,阻塞和非阻塞。

在阻塞模式下,在I/O操作完成前,执行操作的Winsock函数会一直等待下去,不会立即返回程序(将控制权交还给程序)。

而在非阻塞模式下,Winsock函数无论如何都会立即返回。

⏹WindowsSockets为了支持Windows消息驱动机制,使应用程序开发者能够方便地处理网络通信,它对网络事件采用了基于消息的异步存取策略。

⏹WindowsSockets的异步选择函数WSAAsyncSelect()提供了消息机制的网络事件选择,当使用它登记的网络事件发生时,Windows应用程序相应的窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。

intWSAEnumProtocols(LPINTlpiProtocols,LPWSAPROTOCOL_INFOlpProtocolBuffer,ILPDWORDlpdwBufferLength);

⏹Win32平台支持多种不同的网络协议,采用Winsock2,就可以编写可直接使用任何一种协议的网络应用程序了。

通过WSAEnumProtocols函数可以获得系统中安装的网络协议的相关信息。

⏹lpiProtocols,一个以NULL结尾的协议标识号数组。

这个参数是可选的,如果lpiProtocols为NULL,则返回所有可用协议的信息,否则,只返回数组中列出的协议信息。

⏹lpProtocolBuffer,[out],一个用WSAPROTOCOL_INFO结构体填充的缓冲区。

WSAPROTOCOL_INFO结构体用来存放或得到一个指定协议的完整信息。

⏹lpdwBufferLength,[in,out],在输入时,指定传递给WSAEnumProtocols()函数的lpProtocolBuffer缓冲区的长度;

在输出时,存有获取所有请求信息需传递给WSAEnumProtocols()函数的最小缓冲区长度。

这个函数不能重复调用,传入的缓冲区必须足够大以便能存放所有的元素。

这个规定降低了该函数的复杂度,并且由于一个机器上装载的协议数目往往是很少的,所以并不会产生问题。

下面采用异步套接字编写一个网络聊天室程序:

新建一个基于对话框的程序:

在BOOLCChatApp:

:

InitInstance()中加入:

WORDwVersionRequested;

WSADATAwsaData;

interr;

wVersionRequested=MAKEWORD(2,2);

//最高版本

err=WSAStartup(wVersionRequested,&

wsaData);

if(err!

=0)

returnFALSE;

if(LOBYTE(wsaData.wVersion)!

=2||

HIBYTE(wsaData.wVersion)!

=2)

WSACleanup();

在stdafx.h中加入:

WINSOCK2.H>

再LINKWs2_32.lib

给CChatApp增加一个析构函数,在此函数中终止对套接字库的使用:

CChatApp:

~CChatApp()

WSACleanup();

为CChatDlg增加private:

SOCKETm_socket;

在CChatDlg:

CChatDlg中对套接字进行初始化。

m_socket=0;

在析构函数中关闭套接字:

CChatDlg:

~CChatDlg()

if(m_socket)

closesocket(m_socket);

}

在CChatDlg中增加BOOLCChatDlg:

InitSocket()函数。

函数代码如下:

BOOLCChatDlg:

InitSocket()

m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);

if(INVALID_SOCKET==m_socket)

MessageBox("

创建套接字失败!

SOCKADDR_INskaddr;

skaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

skaddr.sin_family=AF_INET;

skaddr.sin_port=htons(6000);

if(SOCKET_ERROR==bind(m_socket,(SOCKADDR*)&

skaddr,sizeof(SOCKADDR_IN)))

绑定失败!

if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ))//一旦有FD_READ事件发生,系统就会触发这个事件,

//系统就会通过UM_SOCK消息通知我们,在这个消息的响应函数中,接收数据就能收到数据。

注册网络读取事件失败!

returnTRUE;

在BOOLCChatDlg:

OnInitDialog()中加入

InitSocket();

在ChatDlg.h加入:

#defineUM_SOCKWM_USER+1

afx_msgvoidOnSock(WPARAMwParam,LPARAMlParam);

在BEGIN_MESSAGE_MAP(CChatDlg,CDialog)中加上红色的那句

//{{AFX_MSG_MAP(CChatDlg)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

//}}AFX_MSG_MAP

ON_COMMAND(UM_SOCK,OnSock)

END_MESSAGE_MAP()

将接收编辑框的多行属性选上。

voidCChatDlg:

OnSock(WPARAMwParam,LPARAMlParam)

switch(LOWORD(lParam))

caseFD_READ:

WSABUFwsabuf;

wsabuf.buf=newchar[200];

wsabuf.len=200;

DWORDdwRead;

DWORDdwFlag=0;

SOCKADDR_INaddrFrom;

intlen=sizeof(SOCKADDR);

CStringstr;

CStringstrTemp;

HOSTENT*pHost;

if(SOCKET_ERROR==WSARecvFrom(m_socket,&

wsabuf,1,&

dwRead,&

dwFlag,

(SOCKADDR*)&

addrFrom,&

len,NULL,NULL))

MessageBox("

接收数据失败!

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("

pHost->

h_name,wsabuf.buf);

str+="

\r\n"

;

GetDlgItemText(IDC_EDIT_RECV,strTemp);

str+=strTemp;

SetDlgItemText(IDC_EDIT_RECV,str);

break;

OnBtnSend()

//TODO:

Addyourcontrolnotificationhandlercodehere

DWORDdwIP;

CStringstrSend;

WSABUFwsabuf;

DWORDdwSend;

intlen;

CStringstrHostName;

SOCKADDR_INaddrTo;

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,&

dwSend,0,

(SOCKADDR*)&

addrTo,sizeof(SOCKADDR),NULL,NULL))

发送数据失败!

return;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 自然科学 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1