线程同步与异步套接字编程
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( 2, 2 );
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
线程同步与异步套接字编程相关推荐
- 《VC++深入详解》学习笔记 第十六章 线程同步与异步套接字编程
(颠簸喜悲幽若尽是无情人) 事件对象成员: 包含(使用计数.事件类型.事件状态) 事件类型: 人工重置的事件对象:得到通知时,等待的所有线程都变为可调度 自动重置的事件对象:得到通知时,等待的 ...
- 孙鑫MFC笔记之十四--多线程同步与异步套接字编程
线程同步有三种方式: 1. 互斥对象涉及方法: HANDLE hMutex=CreateMutex(NULL,FALSE,NULL); //第二个参数为FALSE,将互斥对象声明为空闲状态 ...
- MFC(线程同步与异步套接字,孙鑫C++第十六讲笔记整理)
1.事件对象:来实现线程的同步.与互斥对象一样均属于内核对象. 当人工重置有信号时,所有线程均得到信号,所以不能设为人工重置.代码就不贴了,通过创建匿名的事件对象,也可以让一个程序只能运行一个实例. ...
- MFC(线程同步与异步套接字,孙鑫C++第十六讲笔记整理) - 阿飞的麦克风 - 博客频道...
http://blog.csdn.net/zh634455283/article/details/7893831
- 写的非常不错的一篇阻塞与非阻塞、同步与异步套接字之间的区别
当你发现自己最受欢迎的一篇blog其实大错特错时,这绝对不是一件让人愉悦的事. < IO - 同步,异步,阻塞,非阻塞 >是我在开始学习epoll和libevent的时候写的,主要的思路来 ...
- C# 网络编程之套接字编程基础知识
最近阅读了周存杰编写的<C#网络编程实例教程>并阅读了很多相关方面的资料,同时自己也做了一些套接字编程方面的C#程序,所以根据它的知识总结了最近的套接字编程的一些知识点,方便自己的理解与他 ...
- 关于.NET中socket中的异步套接字的研究二
三 异步套接字 虽然还有许多别的方法解决同步套接字中的问题的方法,但是综合比较来看,异步套接字无疑是大多数情况下最好的解决办法,这个问题稍后讨论. 1 原理 首先来说一下异步的原理(根据自己的理解写的 ...
- 套接字编程-TCP网络编程
文章目录 套接字地址结构 通用套接字地址数据结构 以太网协议的套接字地址数据结构 Netlink协议套接字地址结构 TCP网络编程 套接字初始化socket() domain type protoco ...
- MFC—windows套接字编程
Windows 套接字编程 一.常见概念 1.Windows Sockets 规范 Windows Sockets 规范是 Windows 平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克 ...
最新文章
- 程序员面试题精选100题(53)-C++/C#面试题(2)
- weblogic部署ssh2应用出现异常
- Webstorm 10.0.4 配置
- Scala入门到精通——第十六节 泛型与注解
- 从javaagent迁移到JVMTI:我们的经验
- *hdu5632Rikka with Array
- 女孩和程序员相亲,吃饭消费了380,他没结账就先走,晚上收到微信愣了
- TensorFlow可以“预装”数据集了,新功能Datasets出炉
- R语言-异常数据处理3
- [转载] python字符串转化为16进制数_python实用知识,数值类型和进制整数的转换
- java基础 Day05 内部类、Object类、匿名内部类;方法的覆写;抽象类和接口
- 计算机室管理员考核细则,宿舍管理员量化考核细则
- 拼多多商品链接怎么打开链接下架怎么回事拼多多商品竞价怎么玩需要哪些流程
- 统计学简介之九——两个总体参数的区间估计
- Intouch2020与施耐德PLC通讯
- 计算机面板上英文字母的意识,电脑键盘上有英语的汉语的意识
- 切换日语输入法找不到MicrosoftIME键盘选项了
- 【OpenCV】IPCamera读取网络摄像头实时画面
- Build Library By xcodebuild
- Program Files 目录的dos文件名模式下的缩写PROGRA~1
热门文章
- python3中的zip_Python3实现将文件归档到zip文件及从zip文件中读取数据的方法
- html 选中状态,html默认选中状态
- spring注入普通java类_普通java类如何取得注入spring Ioc容器的对象
- html 手机分辨率,移动端各种分辨率手机屏幕----适配方法集锦
- 2014 网选 5014 Number Sequence(异或)
- protobuf版本常见问题
- (2021) 24 [持久化] 文件系统API
- 已知a类被打包在packagea_2021考研干货:199管理类联考综合逻辑归纳习题(1)
- sql同时操作两列_怎么在两列同时筛选数据库
- python实现表格线性回归_Python实现线性回归