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(); 
    .......... 
    .......... 
} 
添加虚函数:
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!