利用CreateEvent函数,创建线程互斥执行,是线程同步的另一种方式,(锁机制);
#include <windows.h>
#include <iostream.h>
DWORD WINAPI func1proc(LPVOID lpParameter);
DWORD WINAPI func2proc(LPVOID lpParameter);
int tickets=100;
HANDLE h_hevent;//保存时间对象的句柄,
void main()
{
HANDLE hthread1;
HANDLE hthread2;
hthread1=CreateThread(NULL,0,func1proc,NULL,0,NULL);//创建一个线程
hthread2=CreateThread(NULL,0,func2proc,NULL,0,NULL);
CloseHandle(hthread1);
CloseHandle(hthread2);
// h_hevent=CreateEvent(NULL,TRUE,FALSE,NULL);//此处创建的是人工重置事件,不能满足要求,因为会输出0状态,人工事件,除非显示调用resentevent,否则一直处于有信号的状态,因此此处建立自动重置事件;
h_hevent=CreateEvent(NULL,FALSE,FALSE,NULL);//创建自动重置事件;
SetEvent(h_hevent);//讲事件状态设置成有信号状态;
Sleep(400);
CloseHandle(h_hevent);
}
DWORD WINAPI func1proc(
LPVOID lpParameter // thread data
)
{
while(true)
{
WaitForSingleObject(h_hevent,INFINITE);//等待事件有效信号
//ResetEvent()
if (tickets>0)
{
Sleep(1);
cout<<"thread1 sells tickets:"<<tickets--<<endl;
}
else
break;
//ReleaseMutex(h_hevent);//释放互斥锁,因为他们访问了一个统一的全局变量ticket,释放必须遵循谁拥有,谁释放的原则;
//ResetEvent(h_hevent);
SetEvent(h_hevent);//重新设置事件状态为有信号
}
return 0;
}
DWORD WINAPI func2proc(
LPVOID lpParameter // thread data
)
{
while(true)
{
WaitForSingleObject(h_hevent,INFINITE);
if (tickets>0)
{
Sleep(1);
cout<<"thread2 sells tickets:"<<tickets--<<endl;
}
else
break;
// ReleaseMutex(h_hevent);
//ResetEvent(h_hevent);
SetEvent(h_hevent);//重设状态有信号事件
}
return 0;
}
//通过创建一个有名事件来实现只有一个实例执行
//通过创建一个命名的事件来实现只有一个实例执行的
h_hevent=CreateEvent(NULL,TRUE,FALSE,"ticket");
if (h_hevent)//判断是否有值
{
if (GetLastError()== ERROR_ALREADY_EXISTS)//判断是否已经在执行;
{
cout<<"only one instance running!"<<endl;
return;
}
}
=====================================================================================================
关键代码段(临界区)同步进程;
VOID InitializeCriticalSection(//初始化代码段
LPCRITICAL_SECTION lpCriticalSection //[out] critical section,使用之前要构造
);
VOID EnterCriticalSection(//进入关键代码段(临界区)
LPCRITICAL_SECTION lpCriticalSection // critical section
);
VOID LeaveCriticalSection(//离开关键代码段(临界区)
LPCRITICAL_SECTION lpCriticalSection // critical section
);
VOID DeleteCriticalSection(//删除关键代码段(临界区)
LPCRITICAL_SECTION lpCriticalSection // critical section
);
对共同访问的关键区代码,成对添加;
比较:
互斥对象,事件对象,关键代码段的比较
n 互斥对象和事件对象都属于内核对象,利用内核对象进行线程同步时,较慢,但利用互斥对象和事件对象这俗人内核对象,可以在多个进程中的各个纯种间进行同步
n 关键代码段工作在用户方式下,同步速度快,但很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值
==================================================================================================================
利用基于消息的异步套接字编程建立一个网络聊天程序;
1.建立模板和第一个聊天程序相同,
2,然后添加 家在socket版本信息的内容于initInstance()
BOOL CChat_asyApp::InitInstance()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return FALSE;
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
WSACleanup( );
return FALSE;
}
4,在chatDlg里面添加成员变量m_socket和initsock()函数,初始化socket相关信息
BOOL CChat_asyDlg::InitSocket()
{
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);//利用wsasocket来创建套接字的部分
if (INVALID_SOCKET==m_socket)
{
MessageBox("创建套接字失败!");
return FALSE;
}
//绑定套接字的信息
SOCKADDR_IN addrsock;
addrsock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrsock.sin_family=AF_INET;
addrsock.sin_port=htons(6000);
if (SOCKET_ERROR==bind(m_socket,(sockaddr*)&addrsock,sizeof(sockaddr)))
{
MessageBox("绑定套接字失败~!");
return FALSE;
}
//调用wsaselect函数请求一个基于消息的网络通知;
if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ))//FD_READ注册一个读取的事件
{
MessageBox("注册网路读取事件失败");
return FALSE;
}
return TRUE;
}
5 在InitChatDlg(0里面调用initsock()函数;
6添加消息映射函数和定义消息;
ON_MESSAGE(WM_SOCK,OnSock)//消息映射
#d#define WM_SOCK WM_USER+1
7,添加消息响应函数,并实现之;
afxafx_msg void OnSock(WPARAM,LPARAM);//创建标准消息响应函数
void CChat_asyDlg::OnSock(WPARAM wParam,LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ://接受数据,
WSABUF wsabuf;
wsabuf.buf=new char[200];
wsabuf.len=200;
DWORD dwRead;
DWORD dwFlag=0;
SOCKADDR_IN addrFrom;//到来的地址信息
int len=sizeof(sockaddr);
CString str;
if(WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag,(sockaddr*)&addrFrom,&len,NULL,NULL)==SOCKET_ERROR)
{
MessageBox("读取失败");
return;
}
str.Format("%s 说:%s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
CString strTemp;
str+="\r\n";
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
break;
}
}
7 添加“send”按钮的消息函数;(将获得的消息输出到对话框上)
void CChat_asyDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
DWORD dwIP;//接收IP地址;
CString strsend;
WSABUF wsabuf;
DWORD dwSend;//存放实际发送的字节数
int len;
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); /*得到指向CWND的指针,然后强制转换为IP控制*/
SOCKADDR_IN addrTo;
addrTo.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
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;//"\0"
//发送数据
WSASendTo(m_socket,&wsabuf,1,&dwSend,0,(sockaddr*)&addrTo,sizeof(sockaddr),NULL,NULL);
SetDlgItemText(IDC_EDIT_SEND,"");
}
(未完全理解)
1