多线程程序的编写,多线程应用中容易出现的问题。互斥对象的讲解,如何使用互斥对象来实现多线程的同步。如何利用命名互斥对象保证应用程序只有一个实例运行。应用多线程编写网络聊天室程序。
互斥对象
互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。
互斥对象包含一个使用数量,一个线程ID和一个计数器。
ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。
- #include <windows.h>
- #include <iostream.h>
- //声明线程入口函数原型
- DWORD WINAPI Fun1Proc( LPVOID lpParameter );
- DWORD WINAPI Fun2Proc( LPVOID lpParameter );
- int tickets = 100; //要销售的票数还剩下100张
- //这100张票由Fun1Proc与Fun2Proc两个线程负责销售
- HANDLE hMutex;//互斥对象句柄
- void main()
- {
- HANDLE hThread1,hThread2;
- hThread1 = CreateThread( //创建线程
- NULL, //使用缺省的安全性
- 0, //指定初始提交栈的大小
- Fun1Proc,//指定线程入口函数地址
- NULL, //传递给线程的参数
- 0, //附加标记,0表示线程创建后立即运行。值为CREATE_SUSPENDED,创建一个挂起的线程
- NULL); //线程ID,在Win98/95中不能设置为NULL
- CloseHandle(hThread1);
- hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
- CloseHandle(hThread2);
- // cout<<"main thread is running"<<endl;
- // hMutex = CreateMutex(NULL, FALSE,NULL); //创建一个匿名的互斥对象
- //创建一个命名的互斥对象
- hMutex = CreateMutex(NULL,//默认安全性
- TRUE,//初始拥有者,调用线程拥有所用权
- "MuName");//命名的互斥对象
- if(hMutex) //是程序只能运行一次
- {//判断是不是第一次创建的互斥对象
- if(ERROR_ALREADY_EXISTS == GetLastError())
- {//如果为真,说明互斥对象已经创建
- cout<<"已经有一个实例在运行了,只能有一个实例运行同时运行。"<<endl;
- return;
- }
- }
- WaitForSingleObject(hMutex,INFINITE);
- //因为请求的互斥对象线程ID与拥有互斥对象线程ID相同,
- //可以再次请求成功,计数器加1
- ReleaseMutex(hMutex); //第一次释放,计数器减1,但仍有信号
- ReleaseMutex(hMutex); //再一次释放,计数器为零
- while(tickets>0) { Sleep(4000);}
- }//endof main()
- /*------------实现线程入口函数Fun1Proc---------------*/
- DWORD WINAPI Fun1Proc( LPVOID lpParameter )
- {
- while(TRUE)
- {
- //请求互斥对象
- WaitForSingleObject(hMutex,//处于未通知的状态则等待
- INFINITE);//时间流逝则返回,INFINITE永远等待
- if(tickets>0)
- {Sleep(1);
- cout<<"thread 1 sell ticket: ";
- cout<<tickets--<<endl;
- }
- else
- break;
- ReleaseMutex(hMutex);//释放互斥对象
- }
- return 0;
- } ///endof Fun1Proc()
- /*-----------实现线程入口函数Fun2Proc--------------*/
- DWORD WINAPI Fun2Proc( LPVOID lpParameter )
- {
- while(TRUE)
- {
- WaitForSingleObject(hMutex,INFINITE);
- if(tickets>0)
- {Sleep(1);
- cout<<"thread 2 sell ticket: ";
- cout<<tickets--<<endl;
- }
- else
- break;
- ReleaseMutex(hMutex);
- }
- return 0;
- } ///endof Fun1Proc()
- BOOL CChatApp::InitInstance()//注意要包含#include <AfxSock.h>
- {
- if(!AfxSocketInit())//加载套接字库,进行版本协商,可以确保程序结束终结套接字库
- {
- AfxMessageBox("加载套接字失败!");
- return FALSE;
- }
- }
- BOOL CChatDlg::InitSocket()
- {//初始化套接字:
- SOCKET m_socket;
- m_socket = socket(AF_INET,SOCK_DGRAM,0);
- if(INVALID_SOCKET == m_socket)
- {
- AfxMessageBox("套接字创建失败");
- 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);
- //INADDR_ANY表示接收任意IP地址
- //绑定
- int retval;//用来接收bind返回值
- retval=bind(m_socket,(SOCKADDR*)&addrSock,
- sizeof(SOCKADDR));
- if(SOCKET_ERROR==retval)
- {//绑定失败
- closesocket(m_socket);
- AfxMessageBox("绑定失败");
- return FALSE;
- }
- return TRUE;
- }