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

1.利用事件对象来实现线程间的同步

新建一个win32 console application,取名Event,再建一个Event源文件,编辑:

#include <iostream.h> 
#include <windows.h> 
 
DWORD WINAPI Fun1Proc(LPVOID lpParameter); 
DWORD WINAPI Fun2Proc(LPVOID lpParameter); 
 
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,TRUE,FALSE,NULL);//
创建一个匿名的有信号状态的事件对象 
    //g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);//
创建一个匿名的无信号状态的事件对象 
    g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");//
创建一个命名的无信号状态的事件对象 
    SetEvent(g_hEvent);//
将事件对象设置为有信号状态 
    if(g_hEvent) 
    { 
        if(ERROR_ALREADY_EXISTS==GetLastError()) 
        { 
            cout<<"only one instance can run!"<<endl; 
            return
        } 
    } 
 
    Sleep(4000); 
    CloseHandle(g_hEvent); 

 
DWORD WINAPI Fun1Proc( 
  LPVOID lpParameter   // thread data 


    while(TRUE) 
    { 
        WaitForSingleObject(g_hEvent,INFINITE); 
//        ResetEvent(g_hEvent);//
将事件对象设为非信号状态  
        if(tickets>0
        { 
            Sleep(1); 
            SetEvent(g_hEvent); 
            cout<<"thread1 sell ticket : "<<tickets--<<endl; 
        } 
        else 
        { 
            SetEvent(g_hEvent);//
将事件对象设为有信号状态  
            break
        } 
    } 
     
    return 0

 
DWORD WINAPI Fun2Proc( 
  LPVOID lpParameter   // thread data 


     
    while(TRUE) 
    { 
        WaitForSingleObject(g_hEvent,INFINITE); 
//        ResetEvent(g_hEvent);//
将事件对象设为非信号状态 
        if(tickets>0
        { 
            Sleep(1); 
            SetEvent(g_hEvent); 
            cout<<"thread2 sell ticket : "<<tickets--<<endl; 
        } 
        else 
        { 
            SetEvent(g_hEvent);//
将事件对象设为有信号状态 
            break
        } 
    } 
    return 0
}

 

2.利用CriticalSection实现线程同步

#include <iostream.h> 
#include <windows.h> 
 
DWORD WINAPI Fun1Proc(LPVOID lpParameter); 
DWORD WINAPI Fun2Proc(LPVOID lpParameter); 
 
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);//
获得临界区的所有权,进入临界区 
        if(tickets>0
        { 
            Sleep(1); 
            cout<<"thread1 sell ticket : "<<tickets--<<endl; 
        } 
        else 
        { 
            break
        } 
        LeaveCriticalSection(&g_cs);//
离开临界区,并释放所有权 
    } 
     
    return 0

 
DWORD WINAPI Fun2Proc( 
  LPVOID lpParameter   // thread data 


     
    while(TRUE) 
    { 
        EnterCriticalSection(&g_cs);//
获得临界区的所有权,进入临界区 
        if(tickets>0
        { 
            Sleep(1); 
            cout<<"thread2 sell ticket : "<<tickets--<<endl; 
        } 
        else 
        { 
            break
        } 
        LeaveCriticalSection(&g_cs);//
离开临界区,并释放所有权 
    } 
    return 0
}

 

3.线程死锁

#include <iostream.h> 
#include <windows.h> 
 
DWORD WINAPI Fun1Proc(LPVOID lpParameter); 
DWORD WINAPI Fun2Proc(LPVOID lpParameter); 
 
int tickets=100
 
CRITICAL_SECTION g_csA; //
定义一个全局的临界区对象 
CRITICAL_SECTION g_csB; 
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_csA);//
初始化一个临界区对象 
    InitializeCriticalSection(&g_csB); 
    Sleep(4000); 
 
    DeleteCriticalSection(&g_csA);//
释放这个临界区对象 
    DeleteCriticalSection(&g_csB); 

 
DWORD WINAPI Fun1Proc( 
  LPVOID lpParameter   // thread data 


    while(TRUE) 
    { 
        EnterCriticalSection(&g_csA);//
获得临界区的所有权,进入临界区 
        Sleep(1); 
        EnterCriticalSection(&g_csB); 
        if(tickets>0
        { 
            Sleep(1); 
            cout<<"thread1 sell ticket : "<<tickets--<<endl; 
        } 
        else 
            break
        LeaveCriticalSection(&g_csB);//
离开临界区,并释放所有权 
        LeaveCriticalSection(&g_csA); 
    } 
        return 0

 
DWORD WINAPI Fun2Proc( 
  LPVOID lpParameter   // thread data 


     
    while(TRUE) 
    { 
        EnterCriticalSection(&g_csB);//
获得临界区的所有权,进入临界区 
        Sleep(1); 
        EnterCriticalSection(&g_csA); 
        if(tickets>0
        { 
            Sleep(1); 
            cout<<"thread2 sell ticket : "<<tickets--<<endl; 
        } 
        else 
            break
        LeaveCriticalSection(&g_csA);//
离开临界区,并释放所有权 
        LeaveCriticalSection(&g_csB); 
    } 
    return 0
}

 

4.利用异步套接字编写网络聊天室程序

新建一个基于单文档的MFC的应用程序,取名叫Chat2,编辑资源,如下图:

 

在预编译头文件中添加:

#include <winsock2.h> //使用winsock函数要使用它 
#pragma comment(lib,"Ws2_32.lib"

 

编辑函数InitInstance

BOOL CChat2App::InitInstance() 

    WORD wVersionRequested; 
    WSADATA wsaData; 
    int err; 
     
    wVersionRequested = MAKEWORD( 22 ); 
     
    err = WSAStartup( wVersionRequested, &wsaData ); 
    if ( err != 0 )  
    {         
        return FALSE; 
    } 
     
    if ( LOBYTE( wsaData.wVersion ) != 2 || 
        HIBYTE( wsaData.wVersion ) != 2 ) { 
        WSACleanup( ); 
        return FALSE;  
    } 
 
    AfxEnableControlContainer(); 
    .......... 
    .......... 
}

 

添加虚函数:

Chat2.h中编辑:

class CChat2App : public CWinApp 

public
    CChat2App(); 
    ~CChat2App();//
增加一个析构函数,去调用WSACleanup 
    .......... 
    .......... 

Chat2.cpp中编辑:

CChat2App::~CChat2App()

{

    WSACleanup();

}

 

并在CChat2Dlg.h中添加:

public
    CChat2Dlg(CWnd* pParent = NULL);    // standard constructor 
    ~CChat2Dlg();//
析构函数 
 private
    SOCKET m_socket; 

CChat2Dlg.cpp中添加:

CChat2Dlg::~CChat2Dlg() 

    if(m_socket) 
    { 
        closesocket(m_socket); 
    } 
}

 

再添加成员函数BOOL CChat2Dlg::InitSocket,编辑:

BOOL CChat2Dlg::InitSocket() 

    m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0); 
    if(INVALID_SOCKET==m_socket) 
    { 
        MessageBox("
创建套接字失败!"); 
        return FALSE; 
    } 
    SOCKADDR_IN addrSock; 
    addrSock.sin_addr.S_un.S_addr=htol(INADDR_ANY); 
    addrSock.sin_family=AF_INET; 
    addrScok.sin_port=htons(6000); 
    if(SOCKET_ERROR==bind(m_socket,(SOCKET*)&addrSock,sizeof(SOCKADDR))) 
    { 
        MessageBox("
绑定失败"); 
        return FALSE; 
    } 
    if(SOCKET_ERROR==WSAAsyncSelect(m_socket,m_hWnd,WM_SOCK,FD_READ))//
请求一个基于消息的网络读取事件通知 
    { 
        MessageBox("
注册网络读取事件失败!"); 
        return FALSE; 
    } 
    return TRUE; 
}

并在BOOL CChat2Dlg::OnInitDialog()调用一下:

BOOL CChat2Dlg::OnInitDialog() 

    .............. 
    .............. 
    // TODO: Add extra initialization here 
    InitSocket(); 
    return TRUE;  // return TRUE  unless you set the focus to a control 
}

 

接着编写WM_SOCK消息:

Chat2Dlg.h中添加:

#define UM_SOCK WM_USER+1 //消息定义 

afx_msg void OnSock(WPARAM,LPARAM);//
消息函数声明

 

Chat2Dlg.cpp中编辑:

添加消息映射:

BEGIN_MESSAGE_MAP(CChat2Dlg, CDialog) 
    //{{AFX_MSG_MAP(CChat2Dlg) 
    ON_WM_SYSCOMMAND() 
    ON_WM_PAINT() 
    ON_WM_QUERYDRAGICON() 
    //}}AFX_MSG_MAP 
    ON_MESSAGE(UM_SOCK,OnSock) //
消息映射 
END_MESSAGE_MAP() 

消息函数实现:

void CChat2Dlg::OnSock(WPARAM wParam,LPARAM lParama) 

    switch(LOWORD(lParama)) 
    { 
    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; 
        CString strTemp; 
        if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag, 
            (SOCKADDR*)&addrFrom,&len,NULL,NULL))//
接收数据,并判断 
        { 
            MessageBox("
接收数据失败"); 
            return ; 
        } 
        str.Format("%s
说:%s",inet_ntoa(addrFrom.sin_addr),wsabuf.buf); 
        str+="\r\n"
        GetDlgItemText(IDC_EDIT_RECV,strTemp); 
        str+=strTemp; 
        SetDlgItemText(IDC_EDIT_RECV,str); 
        break
    } 
}

 

双击发送按钮,接下来编写发送端:

void CChat2Dlg::OnBtnSend()  

    // TODO: Add your control notification handler code here 
    DWORD dwIP; 
    CString strSend;//
用于存放发送的字节数 
    WSABUF wsabuf; 
    DWORD dwSend; 
    int len; 
    ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); 
     
    SOCKADDR_IN addrTo; 
    addrTo.sin_addr.S_un.S_addr=htonl(dwIP); 
    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'作为结尾 
 
    SetDlgItemText(IDC_EDIT_SEND,""); 
    if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0
        (SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))//
发送数据,并判断 
    { 
        MessageBox("
发送数据失败"); 
        return
    } 
}

 

5.利用主机名发送数据

void CChat2Dlg::OnSock(WPARAM wParam,LPARAM lParama) 

    switch(LOWORD(lParama)) 
    { 
    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; 
        CString strTemp; 
        HOSTENT *pHost;//
定义一个HOSTENT结构体指针 
        if(SOCKET_ERROR==WSARecvFrom(m_socket,&wsabuf,1,&dwRead,&dwFlag, 
            (SOCKADDR*)&addrFrom,&len,NULL,NULL))//
接收数据,并判断 
        { 
            MessageBox("
接收数据失败"); 
            return ; 
        } 
        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("%s
说:%s",pHost->h_name,wsabuf.buf); 
        str+="\r\n"
        GetDlgItemText(IDC_EDIT_RECV,strTemp); 
        str+=strTemp; 
        SetDlgItemText(IDC_EDIT_RECV,str); 
        break
    } 

void CChat2Dlg::OnBtnSend()  

    // TODO: Add your control notification handler code here 
    DWORD dwIP; 
    CString strSend;//
用于存放发送的字节数 
    WSABUF wsabuf; 
    DWORD dwSend;//
用于指向存放the number of bytes sent by this call 
    int len; 
    CString strHostName; 
    SOCKADDR_IN addrTo; 
    HOSTENT* pHost;//
定义一个HOSTENT结构体 
    if(GetDlgItemText(IDC_EDIT_HOSTNAME,strHostName),strHostName=="NULL")//
获取主机名,并判断其是否为空 
    { 
        ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP);//
IP地址控件中获取IP地址 
        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]); 
    } 
 
    ((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); 
     
    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'作为结尾 
 
    SetDlgItemText(IDC_EDIT_SEND,""); 
    if(SOCKET_ERROR==WSASendTo(m_socket,&wsabuf,1,&dwSend,0
        (SOCKADDR*)&addrTo,sizeof(SOCKADDR),NULL,NULL))//
发送数据,并判断 
    { 
        MessageBox("
发送数据失败"); 
        return
    } 
}

 

运行,OK!

转载于:https://www.cnblogs.com/luowei010101/archive/2011/04/27/2030829.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/548939.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑数据存储工具----光盘驱动器

作者&#xff1a;Liuweifei 电脑数据存储工具----光盘驱动器 光盘驱动器简称光驱&#xff0c;是电脑用来读写光盘内容的设备&#xff0c;也是在台式机和笔记本电脑里比较常见的一个硬件&#xff0c;随着移动存储设备的快速发展&#xff0c;光驱逐渐被其取代。 1. 光驱的类型…

认识和选购显卡

作者&#xff1a;Liuweifei 认识和选购显卡 显卡一般是一块独立的电路板&#xff0c;插在主板上接收由主机发出的控制显示系统工作的指令和显示内容的数字信号&#xff0c;然后通过输出模拟&#xff08;或数字&#xff09;信号控制显示器显示各种字符和图形&#xff0c;它和显…

多媒体融合通信平台促进公网和专网的互联互通

在发生诸如地震、洪涝灾害以及极端天气的情况下&#xff0c;由于通信设施和电力设施最容易遭到破坏&#xff0c;因此&#xff0c;在进行应急救援时&#xff0c;相关指挥部门最先想到的就是进行相应设施的抢修。 公网抢修成功&#xff0c;所有相关抢险救灾者都可以实现互相通话&…

ECMAScript 的未来:预测 JavaScript 创新的下一个浪潮

以下是简单概括关于JavaScript知识点以及一些目前比较流行的比如&#xff1a;es6 想要系统学习&#xff1a; 大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&…

利用Visio 2007图形化项目进度和项目跟踪

课程类型 Microsoft Office Visio 2007 视频时长 120分钟 播放 课程资料 课程简介&#xff1a; 在进行项目管理时&#xff0c;项目经理将使用Microsoft Project对项目进行规划、资源分配、成本控制和项目状态跟踪。但是&#xff0c;项目中的数据如何能够通过更图形化的方式呈…

VRP 的发展

随着网络技术和应用的飞速发展&#xff0c;VRP 平台在处理机制、业务能力、产品支持等方面也在持续演进。由于平时也接触到了这几个版本的平台&#xff0c;也常不知道所以然&#xff0c;特找了些资料整理了一下。主要列举了VRP 发展历程中的几个主要版本。 VRP 发展历程 各版本…

PHP学习——定界符格式引起的错误

下面是一个错误的代码&#xff0c;能看出哪里出错了么&#xff1f;&#xff1f;对于我这个初学者什么都是蒙蒙懂的&#xff0c;真的无从下手&#xff0c;但是真的要自己尝试了才知道哪里错了&#xff0c;书和教程都不会告诉我哪里错了 错误代码&#xff1a;Parse error: syntax…

PHP之数组学习

对于网页编程来说&#xff0c;最重要的就是存取和读写数据了。存储方式可能有很多种&#xff0c;可以是字符串、数组、文件的形式等&#xff0c;今天学习了数组&#xff0c;可以说是PHP的数据应用中较重要的一种方式。PHP的数组函数众多&#xff0c;下面是我学习的小结&#xf…

mysql Error 1045(28000)

2019独角兽企业重金招聘Python工程师标准>>> 在windows操作系统安装mysql数据库&#xff0c;碰到Error 1045(28000) Access Denied for user rootlocalhost (Using password:NO)错误时&#xff0c;你需要重新设置密码。 具体方法是&#xff1a; 1.先在安装目录找到m…

给你的博客添加个看电影的频道

PPTV新推出一个Silverlight版PPTV在线剧场&#xff0c;里面电影电视剧和PPTV 软件端同步&#xff0c;只需安装Silverlight软件&#xff0c;即可在线观看。PPTV剧场版网址 为COOL.PPTV.COM &#xff0c;使用iframe代码&#xff0c;嵌入到页面中&#xff0c;给博客网站增加 一个在…

正则表达式生成器

对正则表达式很头疼&#xff0c;是不是&#xff1f;每次看到都觉得像看天书似的&#xff0c;别说让人自己整一个出来了。下面这个网站可以帮你生成正则表达式&#xff0c;而且还可以根据不同的语言生成不同的代码示例&#xff0c;很强大。 http://www.txt2re.com/index.php3 打…

关于面试与被面试

2019独角兽企业重金招聘Python工程师标准>>> 换位思考--开始思考自己&#xff0c;思考他人。缘由是一位刚刚进来没几天的新同事离职了。 首先一个大的前提是&#xff1a;面试是一个双向选择的过程。 假如自己去面试的情况&#xff1a; 1. 对自己的方向有明确的认识&…

淘宝山寨IOS sdk

SDK分享——欢迎大家互助分享2/253 慧修店铺发表于 2011-03-24 16:29iOS的SDK 基于iOS开发的朋友&#xff0c;可以参考iOS的SDK&#xff0c;感谢北京天籁传音数字技术有限公司的杨子刚为大家分享。下载地址&#xff1a;http://download.taobaocdn.com/mtop/release/ApiDemo(ip…

VDI序曲二十七 IE7,IE8,IE9应用程序虚拟化

大家一定很期待我们如果要同时可以打开IE7,IE8,IE9怎么实现对吧&#xff1f; 那好&#xff0c;我就给大家讲下我们的VDI解决方案怎么实现这4种IE9怎么并存打开吧 今天我就讲IE7,IE8,IE9怎么做 我这以IE7为例&#xff1a; 我们用Hyper-V创建虚拟机RDIE7-SRV&#xff0c;系统是Wi…

面板Ext.Panel使用

概要1、Ext.Panel概述2、面板的五大组成部分3、面板的特点4、面板中的内容5、面板内容动态控制6、API概述1、Ext.Panel概述面板Panel是ExtJS控件的基础&#xff0c;很多高级控件都是在面板的基础上扩展的&#xff0c;还有其它大多数控件也都直接或间接与它有关系。应用程序的界…

matlab彩色图像缩放(双线性与双立方插值)

双线性插值原理可以参考这篇博文&#xff1a;双线性内插法 立方插值的推导我参考的这篇文章&#xff1a;Cubic interpolation 数学推导过程上面两篇文章解释得还是比较清楚&#xff0c;可以自己拿笔推一推&#xff0c;至于双线性和双立方可以理解为先行&#xff08;或列&#x…

灵活运用 SQL SERVER FOR XML PATH

FOR XML PATH 有的人可能知道有的人可能不知道&#xff0c;其实它就是将查询结果集以XML形式展现&#xff0c;有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作。那么以一个实例为主. 一.FOR XML PATH 简单介绍 那么还是首先来介绍一下FOR…

LeetCode题库整理【Java】—— 1两数之和

LeetCode题库整理【Java】 1.两数之和 题目&#xff1a;给定一个整数数组和一个目标值&#xff0c;找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案&#xff0c;且同样的元素不能被重复利用。 示例: 给定 nums [2, 7, 11, 15], target 9 因为 nums[0] nu…

poj3749

简单题 View Code #include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>usingnamespacestd;stringst;intmain(){//freopen("t.txt", "r", stdin);while(getline(cin, st)) {if(st "ENDOFINPUT")…

LeetCode题库整理【Java】—— 7整数反转

LeetCode题库整理【Java】 7.整数反转 题目&#xff1a;给出一个32位的有符号整数&#xff0c;你需要将这个这个整数中每位上的数字进行反转。 示例1&#xff1a; 输入&#xff1a; 123 输出&#xff1a; 321 示例2&#xff1a; 输入&#xff1a; -123 输出&#xff1a;…