zoukankan      html  css  js  c++  java
  • vc++学习笔记16 线程同步,异步套接字

    利用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


  • 相关阅读:
    DS博客作业05--查找
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    C博客作业05-指针
    C语言——数组博客作业
    c语言博客3—函数
    循环结构博客
    c语言博客,顺序与分支结构
    Java面向对象课程设计——购物车
  • 原文地址:https://www.cnblogs.com/HuaiNianCiSheng/p/3074713.html
Copyright © 2011-2022 走看看