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

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;它和显…

11.04.30 半夜清晨

好一阵子没来blog了。 没错&#xff0c;间歇性迷茫。 期中考的缘故&#xff0c;两周没碰题。 最近又开始刷usaco&#xff0c;先恢复下手感脑感。 但是&#xff0c;真的是刷题无力。各种无力。 但是呢&#xff0c;哥是不会放弃的&#xff0c;这个不用怀疑。 院科协换届了&#x…

linux输入多行内容至文件

linux输入多行内容至文件 1. 单行写入 [rootcn01 test]# echo "192.168.1.1" >test.txt [rootcn01 test]# cat test.txt 192.168.1.12. 单行追加 [rootcn01 test]# echo "192.168.1.1" >>test.txt [rootcn01 test]# cat test.txt 192.168.1.…

PB-treeview基本属性事件函数

PB-treeview基本属性事件函数编程相关阅读271 评论0 字号&#xff1a;大中小 订阅 2010-11-04 13:43:34Label 项目的标识文字OverlayPictureIndex指定要使用的重叠图片的列表中的图片索引, 该图片显示在正常图片的上边StatePictureIndex 与状态图标列表中某个图标相对…

linux 之sed用法大全

linux 之sed用法大全 sed详细用法 1. sed的作用 sed是Stream Editor&#xff08;流编辑器&#xff09;的缩写&#xff0c;简称流编辑器&#xff1b;主要用来处理文本的。跟awk、grep合起来成为linux三驾马车。 sed是一行一行读取文件内容并按照要求进行处理&#xff0c;把处…

hadoop-0.21.0-eclipse-plugin无法在eclipse中运行解决方案

LINUX下将hadoop-0.21自带的hadoop eclipse plugin放到eclipse dropins目录中无法正常运行&#xff0c;使用eclipse -consolelog 发现找不到hadoop的类&#xff0c;解压hadoop-0.21.0-eclipse-plugin.jar发现META-INF下的MANIFEST.MF文 件中&#xff0c;Bundle-ClassPath写的有…

Linux之grep 命令

Linux之grep 命令 1. grep 简介 [grep] (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具&#xff0c;它能使用正则表达式搜索文本&#xff0c;并把匹配的行打印出来。 命令格式&#xff1a;grep […

网络趋势JSP介绍

JSP简介 JSP(JavaServer Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术&#xff0c;它是在传统的网页HTML文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag)&#xff0c;从而形成JSP文件(*.jsp)。 用J…

linux shell脚本批量创建公钥

linux shell脚本批量创建公钥 为实现对多台服务器部署服务&#xff0c;如果只用交互方式输入密码&#xff0c;耗时耗力&#xff0c;因此必须考虑自动化部署&#xff0c;查询资料发现expect方式可以实现。 一、介绍 expect脚本是Tcl脚本语言的拓展。用来实现自动的交互式任务…

api与sdk

API/SDK API &#xff08;Application Programming Interface&#xff09;应用程序接口SDK&#xff08;Software Development Kit &#xff09;软件开发工具包api就是一个接口&#xff0c;指向应用程序&#xff0c;一般是通过这个接口能够获得这个应用程序的产生或者处理的数据…

MRI骨水肿是早期未分化关节炎演变为RA的独立预测预测因素

原文 译文 Arthritis & Rheumatism DOI: 10.1002/art.30396 MRI bone edema is an independent predictor of development of rheumatoid arthritis in patients with early undifferentiated arthritis 1. Anne Duer-Jensen MD1,*,†, 2. Kim Hrslev-…

linux之awk超详解

linux之awk详解 1、awk简介 awk是一种编程语言&#xff0c;用于linux下对文本和数据进行处理。数据可以来来自标准输入、一个或多个文件&#xff0c;或其他命令的输出。 更多作为脚本来使用。 awk处理数据的方式&#xff1a;逐行扫描文件&#xff0c;寻找匹配的特定模式的行…

Windows2003 企业版 + Sql Server2005手工调整数据库服务器内存

最近犯了一个大的错误&#xff0c;总以为Windows2003 能够合理的使用多余的内存&#xff0c;能够智能化处理内存&#xff0c;事实非然。事情是这样的&#xff0c;我有一台数据库服务器&#xff0c;32位&#xff0c;操作系统是Windows2003企业版&#xff0c;4G内存&#xff0c;3…

docker搭建postgresql 14主从库 及使用shell脚本备份数据库

docker搭建postgresql 14主从库 及使用shell脚本备份数据库 1、地址规划 IP地址名称备注192.168.1.11pg1主库192.168.1.21pg2从库 2、安装部署主库 [rootcn01 ~]# mkdir -p /data/postgressql/data [rootcn01 ~]# docker run --name pgtest --restartalways -v /data/postgr…

VC程序中运行其他程序的三种方法

有三个函数可以使用: WinExec, ShellExecute,CreateProcess 1.WinExec(String lpCmdLine,Long nCmdShow); 参数说明: 参数类型及说明lpCmdLineString&#xff0c;包含要执行的命令行nCmdShowLong&#xff0c;为窗口指定可视性方面的一个命令。请用下述任何一个常数SW_HIDE隐藏窗…

linux shell 判断主机三次存活之批量探测

linux shell 判断主机三次存活之批量探测 在生产环境中&#xff0c;需要查看主机在线情况&#xff0c;之前都是采用执行一次ping命令的方式去操作&#xff0c;会丢失某些存活主机&#xff0c;故改进了脚本采用ping三次的方式进行操作。 #for 语句 #&#xff01;/bin/bash ip_…

linux中单引号、双引号

linux中单引号与双引号的区别和用法 1、单引号 单引号定义为所见即所得&#xff0c;单引号内部的内容原样输出&#xff0c;被单引号引起来的内容不管时变量还是常量都不会发生替换 #在表示连续字符串时&#xff0c;单引号、双引号、无引号都是一样的 [rootcn21 ~]# str1&quo…

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

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

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

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