线程同步与异步套接字编程
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
總結
以上是生活随笔為你收集整理的线程同步与异步套接字编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cisco ios命令
- 下一篇: 三轮哥