本文主要说明了线程间互斥的方法:
1. 互斥量
2. 临界区
3. 事件
进程间互斥的方法:使用进程的互斥对象,防止进程多次实例化;
1. 线程启动
#include <windows.h> //包含相应头文件
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter ); //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter );
int main() //主函数
{
HANDLE h1,h2; //定义句柄变量
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n"); //输出线程1运行信息
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n"); //输出线程2运行信息
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
while(1)
{
if(getchar()=='q') //如果用户输入字符q
{
return 0; //程序正常退出
}
else //如果用户输入的字符不是q
{
::Sleep(100); //程序睡眠
}
}
}
DWORD WINAPI myfun1(LPVOID lpParameter) //分别实现线程函数
{
printf("线程1正在运行!\r\n"); //输出信息
return 0; //正常结束线程函数
}
DWORD WINAPI myfun2(LPVOID lpParameter)
{
printf("线程2正在运行!\r\n");
return 0;
}
2. MFC互斥对象
#include <afxmt.h>
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter);//声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
CMutex hmutex(NULL,FALSE,NULL); //定义全局互斥对象
int a=0; //定义全局变量a
int main()
{
HANDLE h1,h2; //定义线程句柄
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("使用CMutex 类实现线程同步\r\n");
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
return 0;
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
while(1)
{
hmutex.Lock(INFINITE); //锁定互斥对象
if(a<10000)
{
a+=1; //变量自加
::Sleep(1000); //线程睡眠1秒
printf("线程1:%d\r\n",a);
hmutex.Unlock(); //释放互斥对象
}
else
{
hmutex.Unlock(); //释放互斥对象
break; //跳出循环
}
}
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
while(1)
{
hmutex.Lock(INFINITE); //锁定互斥对象
if(a<10000)
{
a+=1;
::Sleep(1000);
printf("线程2:%d\r\n",a); //输出变量
hmutex.Unlock(); //释放互斥对象
}
else
{
hmutex.Unlock(); //释放互斥对象
break; //跳出循环
}
}
return 0; //线程正常退出
}
3. MFC临界区
#include <stdio.h>
#include <afxmt.h>
DWORD WINAPI myfun1(LPVOID lpParameter); //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
CCriticalSection m_Sec; //定义全局变量m_Sec
int a=0;
//定义全局变量a
int main()
{
HANDLE h1,h2; //定义线程句柄
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
return 0;
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
m_Sec.Lock(); //锁定临界区
a+=1; //变量加1
printf("%d\n",a); //输出变量
m_Sec.Unlock(); //对临界区进行解锁
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
m_Sec.Lock(); //锁定临界区
a+=1; //变量加1
printf("%d\n",a); //输出变量
m_Sec.Unlock(); //对临界区进行解锁
return 0;
}
4. MFC事件对象
#include <afxmt.h>
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter);//声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
CEvent event(false,false,NULL,NULL); //将事件对象定义为全局变量
int a=0; //定义全局变量a
int main()
{
HANDLE h1,h2; //定义线程句柄
event.SetEvent();
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
return 0;
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
while(1)
{
::WaitForSingleObject(event.m_hObject,INFINITE); //请求事件对象
//event.ResetEvent(); //设置事件对象为无信号状态
if(a<10000)
{
a+=1; //变量自加
::Sleep(1000); //线程睡眠1秒
printf("线程1:%d\r\n",a); //输出变量
event.SetEvent(); //设置事件对象为有信号状态
}
else
{
event.SetEvent(); //设置事件对象为有信号状态
break; //跳出循环
}
}
return 0; //线程
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
while(1)
{
::WaitForSingleObject(event.m_hObject,INFINITE); //请求事件对象
//event.ResetEvent(); //设置事件对象为无信号状态
if(a<10000)
{
a+=1;
::Sleep(1000);
printf("线程2:%d\r\n",a); //输出变量
event.SetEvent();
}
else
{
event.SetEvent(); //设置事件对象为有信号状态
break; //跳出循环
}
}
return 0; //线程正常退出
}
5. 线程间互斥对象
#include <windows.h> //包含头文件
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter);//声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
HANDLE hmutex;
int a=0; //定义全局变量a
int main()
{
hmutex=::CreateMutex(NULL,FALSE,NULL); //创建互斥对象并返回其句柄
HANDLE h1,h2; //定义线程句柄
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
return 0;
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
while(1)
{
::WaitForSingleObject(hmutex,INFINITE); //请求互斥对象
if(a<10000)
{
a+=1; //变量自加
::Sleep(1000); //线程睡眠1秒
printf("线程1:%d\r\n",a);
::ReleaseMutex(hmutex); //释放互斥对象句柄
}
else
{
::ReleaseMutex(hmutex); //释放互斥对象句柄
break; //跳出循环
}
}
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
while(1)
{
::WaitForSingleObject(hmutex,INFINITE); //请求互斥对象
if(a<10000)
{
a+=1;
::Sleep(1000);
printf("线程2:%d\r\n",a); //输出变量
::ReleaseMutex(hmutex); //释放互斥对象句柄
}
else
{
::ReleaseMutex(hmutex); //释放互斥对象句柄
break; //跳出循环
}
}
return 0; //线程正常退出
}
6. 进程间互斥对象
#include<windows.h> //包含头文件
#include<stdio.h>
int main() //主函数
{
HANDLE hmutex; //定义互斥对象句柄
hmutex=::CreateMutex(NULL,true,"VC网络编程"); //创建互斥对象并返回其句柄
if(hmutex) //判断创建互斥对象是否成功
{
if(ERROR_ALREADY_EXISTS==GetLastError()) //获取错误
{
printf("只允许一个实例程序运行!\r\n"); //打印相关信息
}
else
{
printf("实例程序运行成功!\r\n");
}
}
::ReleaseMutex(hmutex); //释放互斥对象句柄
::Sleep(100000); //使程序睡眠100秒
return 0; //程序正常结束
}
7. 临界区对象
#include <windows.h> //包含头文件
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter );//声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter );
static int a1=0; //定义全局变量并初始化
CRITICAL_SECTION Section; //定义临界区对象
int main() //主函数
{
InitializeCriticalSection(&Section); //初始化临界区对象
HANDLE h1,h2; //定义线程句柄
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
printf("正常退出程序请按\r\n");
while(1)
{
if(getchar()=='q') //如果用户输入字符q
{
DeleteCriticalSection(&Section); //删除临界区对象
return 0;
}
}
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
while(1)
{
EnterCriticalSection(&Section); //进入临界区
a1++; //变量自加
if(a1<10000) //设置变量a1小于10000
{
//::Sleep(1000); //程序睡眠1秒
printf("线程1正在计数%d\r\n",a1);
LeaveCriticalSection(&Section); //离开临界区
}
else //如果变量大于10000
{
LeaveCriticalSection(&Section); //离开临界区
break; //跳出循环
}
}
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
while(1)
{
EnterCriticalSection(&Section); //进入临界区
a1++;
if(a1<10000)
{
//::Sleep(1000); //程序睡眠1秒
printf("线程2正在计数%d\r\n",a1);
LeaveCriticalSection(&Section); //离开临界区
}
else
{
LeaveCriticalSection(&Section);
break;
}
}
return 0; //线程函数返回0
}
8. 事件对象用于线程保护
#include <windows.h> //包含头文件
#include <stdio.h>
DWORD WINAPI myfun1(LPVOID lpParameter);//声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
HANDLE hevent; //定义全局变量hevent
int a=0; //定义全局变量a
int main()
{
HANDLE h1,h2; //定义线程句柄
hevent=::CreateEvent(NULL,false,false,NULL);
::SetEvent(hevent);
h1=::CreateThread(NULL,0,myfun1,NULL,0,NULL); //创建线程1
printf("线程1开始运行!\r\n");
h2=::CreateThread(NULL,0,myfun2,NULL,0,NULL); //创建线程2
printf("线程2开始运行!\r\n");
::CloseHandle(h1); //关闭线程句柄对象
::CloseHandle(h2);
::Sleep(10000); //程序睡眠10秒
return 0;
}
DWORD WINAPI myfun1(LPVOID lpParameter) //线程函数1
{
while(1)
{
::WaitForSingleObject(hevent,INFINITE); //请求事件对象
if(a<10000)
{
a+=1; //变量自加
::Sleep(1000); //线程睡眠1秒
printf("线程1:%d\r\n",a); //输出变量
::SetEvent(hevent); //设置事件对象为有信号状态
}
else
{
::SetEvent(hevent); //设置事件对象为有信号状态
break; //跳出循环
}
}
return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter) //线程函数2
{
while(1)
{
::WaitForSingleObject(hevent,INFINITE); //请求事件对象
if(a<10000)
{
a+=1;
::Sleep(1000);
printf("线程2:%d\r\n",a); //输出变量
::SetEvent(hevent);
}
else
{
::SetEvent(hevent); //设置事件对象为有信号状态
break; //跳出循环
}
}
return 0; //线程正常退出
}