MFC:多线程和网路多线程编程举例

来源:互联网 发布:淮海战役 知乎 编辑:程序博客网 时间:2024/06/11 15:00
<span style="font-size:14px;">
<span style="white-space:pre"></span>多线程编程简例:HANDLE CreateThread(  LPSECURITY_ATTRIBUTES lpsa,     //NULL,使用缺省的安全性  DWORD cbStack,//0,使用和调用线程一样的大小   LPTHREAD_START_ROUTINE lpStartAddr,  //线程的入口函数地址ThreadProc  LPVOID lpvThreadParam,    //线程参数  DWORD fdwCreate,      //CREATE_SUSPENDED:线程创建后不会运行,直到调用ResumeThread;0:创建后立即运行。  LPDWORD lpIDThread    //返回线程ID,可以为NULL.);DWORD WINAPI ThreadProc(  LPVOID lpParameter);HANDLE CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes, //安全属性  BOOL bInitialOwner, //互斥对象的初始拥有者(若为true,需要释放:谁拥有互斥对象谁释放)  LPCTSTR lpName   //互斥对象的名字);//互斥对象属于内核对象,能够确保线程拥有对单个资源的互斥访问权。//互斥对象包含一个使用计数,一个线程ID。//若互斥对象已经存在,返回存在的句柄,调用GetLastError()会返回ERROR_ALREADY_EXISTSDWORD WaitForSingleObject(  HANDLE hHandle,  //互斥对象句柄,若是有信号状态,函数返回;反之,等待  DWORD dwMilliseconds //超时的时间间隔,若时间到,函数返回,即使没信号;0/INFINITE);//当拥有互斥对象的线程请求时,即使是未通知状态,也能请求到,此时使用计数加一BOOL ReleaseMutex(  HANDLE hMutex);//当线程终止时,即使没有释放,操作系统也会将此信号量的线程ID设为0,引用计数设为0/**************************************************************************************************************/eg:多线程举例//win32控制台应用程序#include <windows.h>#include <iostream>using namespace std;DWORD WINAPI Fun1Proc(  LPVOID lpParameter);DWORD WINAPI Fun2Proc(  LPVOID lpParameter);int index = 0;int tickets = 100;HANDLE hMutex;void main(){ HANDLE hThread1;HANDLE hThread2;hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);CloseHandle(hThread1); //线程内核对象的引用计数减一CloseHandle(hThread2);hMutex = CreateMutex(NULL,FALSE,"tickets"); //创建一个命名的互斥对象if(hMutex){  //如果此互斥对象已经存在if(ERROR_ALREADY_EXISTS == GetLastError()){cout << "only one instance can run!" << endl;//只能有一个实例return ;}}Sleep(4000);//保持主线程不要退出,并且不占用CPU时间}DWORD WINAPI Fun1Proc(LPVOID lpParameter  ){while(true){ //让线程不断循环,否则线程函数执行完线程就退出了WaitForSingleObject(hMutex,INFINITE);//注意位置if(tickets > 0){ //若在if语句执行时时间片到,会出现一个座位有两张票情况Sleep(1);//所以要处理线程间的同步互斥:CreateMutex()cout<< "thread1 sell ticket : " << tickets-- << endl;}elsebreak;ReleaseMutex(hMutex);//将线程ID设为0,互斥对象设为已通知状态}return 0;}DWORD WINAPI Fun2Proc(LPVOID lpParameter){while(true){ WaitForSingleObject(hMutex,INFINITE);if(tickets > 0){Sleep(1);cout<< "thread2 sell ticket : " << tickets-- << endl;}elsebreak;ReleaseMutex(hMutex);}return 0;}/**************************************************************************************************************/多线程编写网络聊天室程序(MFC):程序界面如图:<img src="http://img.blog.csdn.net/20141011134431281?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDAwMjcwNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />一、加载套接字BOOL AfxSocketInit(  //MFC提供的加载套接字库1.1版本的函数,用于版本协商   WSADATA* lpwsaData = NULL  ); //Call this function in your CWinApp::InitInstance override to initialize Windows Sockets.//需要包含头文件: #include <Afxsock.h>//加载1.1版本的套接字库struct WSAData {    WORD wVersion;    WORD wHighVersion;    char szDescription[WSADESCRIPTION_LEN+1];    char szSystemStatus[WSASYSSTATUS_LEN+1];    unsigned short iMaxSockets;    unsigned short iMaxUdpDg;    char FAR * lpVendorInfo; };//If lpwsaData is not equal to NULL, then the address of the WSADATA structure is filled by the call to WSAStartup. //This function also ensures that WSACleanup is called for you before the application terminates.二、初始化套接字:1、创建套接字 2、绑定套接字BOOL CChatDlg::initSocket() //在OnInitDialog中调用{m_socket = socket(AF_INET,SOCK_DGRAM,0); //创建套接字if(INVALID_SOCKET == m_socket){MessageBox("套接字创建失败");return false;}SOCKADDR_IN addrSock;addrSock.sin_family = AF_INET;addrSock.sin_port = htons(6000);addrSock.sin_addr.S_un.S_addr = htonl(INADDR_ANY);int retval;retval = bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));//绑定套接字if(SOCKET_ERROR == retval){closesocket(m_socket);MessageBox("绑定失败!");return false;}return true;}三、编写接收端程序(1、创建接收线程 2、编写线程函数(接收消息,给对话框post消息) 3、消息响应函数)//在CChatDialog头文件中定义结构体:struct RECVPARAM{SOCKET sock;HWND hwnd;`f};//在OnInitDialog中:initSocket();RECVPARAM*pRecvParam = new RECVPARAM;pRecvParam->sock = m_socket;pRecvParam->hwnd = m_hWnd; //对话框句柄HANDLE  hThread = CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL); //创建接收线程CloseHandle(hThread); //定义静态的线程函数(成员函数)static DWORD WINAPI RecvProc(LPVOID lpParameter);DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)//在线程函数里接收消息{SOCKET sock = ((RECVPARAM*)lpParameter)->sock;HWND hwnd = ((RECVPARAM*)lpParameter)->hwnd;SOCKADDR_IN addrFrom; //接收发送端的地址信息int len = sizeof(SOCKADDR);//必须初始化char recvBuf[200];char tempBuf[300];int retval;while(true){retval = recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);//接收信息if(SOCKET_ERROR == retval)break;sprintf(tempBuf,"%s say:%s",inet_ntoa(addrFrom.sin_addr),recvBuf);::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf); //给对话框发送消息}return 0;}//1、在CChatDialog头文件中定义消息的值:#define WM_RECVDATA WM_USER+1//2、头文件保护代码的注释宏之间添加消息响应函数原型的声明:afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);//3、源文件消息映射宏之间添加消息映射:ON_MESSAGE(WM_RECVDATA,OnRecvData) //后面不要加分号//4、最后,消息响应函数的实现:void CChatDlg::OnRecvData(WPARAM wParam,LPARAM lparam){CString str = (char*)lparam;CString strTemp; //保存以前接受到的数据GetDlgItemText(IDC_EDIT_RECV,strTemp);str += "\r\n"; //添加换行str += strTemp;SetDlgItemText(IDC_EDIT_RECV,str);}四、编写发送端程序:1、获取编辑框文本 2、发送数据 3、设置编辑框文本void CChatDlg::OnBtnSend() //将“发送”按钮设为默认按钮{DWORD dwIP;((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); //得到的是主机字节序SOCKADDR_IN addrTo;addrTo.sin_family = AF_INET; //地址族addrTo.sin_port = htons(6000); //端口号addrTo.sin_addr.S_un.S_addr = htonl(dwIP); //转换成网络字节序CString strSend;GetDlgItemText(IDC_EDIT_SEND,strSend);sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR)); //发送数据SetDlgItemText(IDC_EDIT_SEND,"");}运行结果:<img src="http://img.blog.csdn.net/20141011134709243?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDAwMjcwNA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" /></span>


0 0
原创粉丝点击