线程同步

绪论

线程同步有四种方式:

  • 临界区(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信号量(CSemaphore)

临界区 CCriticalSection

将同步变量划分到一个区域内。在一个线程访问时,调用CCriticalSection的成员函数lock(),此时如果有其他线层访问,则此线程会被挂起,并且放入一个系统队列中等待。知道当前线程调用Unlock()释放临界区。

CCriticalSection.demo

  • 建立一个基于对话框的工程MultiThread8,在对话框IDD_MULTITHREAD8_DIALOG中加入两个按钮和两个编辑框控件,两个按钮的ID分别为IDC_WRITEW和IDC_WRITED,标题分别为“写‘W’”和“写‘D’”;两个编辑框的ID分别为IDC_W和 IDC_D,属性都选中Read-only;

  • 在MultiThread8Dlg.h文件中声明两个线程函数: UINT WriteW(LPVOID pParam);UINT WriteD(LPVOID pParam); 使用ClassWizard分别给IDC_W和IDC_D添加CEdit类变量m_ctrlW和m_ctrlD;

  • 在 MultiThread8Dlg.cpp文件中添加如下内容:
    为了文件中能够正确使用同步类,在文件开头添加:#include “afxmt.h”

    afxmt是用来创建和管理多线程的。
    afxmt.h是一个MFC多线程同步的一个扩展头文件, 该头文件中声明了用于MFC编程中多线程同步时所需要的类, 比如:
    class CSyncObject;
    class CSemaphore;
    class CMutex;
    class CEvent;
    class CCriticalSection;
    包含该头文件, 就可以直接在自己的程序中使用这几个类!
    afxmt名字解释: afx代表全局的意思, mt是Multi Thread的简写

  • 定义临界区和一个字符数组,为了能够在不同线程间使用,定义为全局变量:CCriticalSection critical_section;char g_Array[10];

    /不能在头文件中定义,会出现error LNK2005: “class CCriticalSection section” (?section@@3VCCriticalSection@@A) already defined in lab.obj的错误,因为连接顺序的问题,所以头文件可以放在任意位置,但是变量的设置必须在cpp文件中。

  • 添加线程函数:

UINT WriteW(LPVOID pParam)
 
{
 
CEdit *pEdit=(CEdit*)pParam;
 
pEdit->SetWindowText("");
 
critical_section.Lock();
 
// 锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
 
//直至执行 critical_section.Unlock();语句
 
for(int i=0;i<10;i++)
 
{
 
g_Array[i]=''W'';
 
pEdit->SetWindowText(g_Array);
 
Sleep(1000);
 
}
 
critical_section.Unlock();
 
return 0;
 
}
 
UINT WriteD(LPVOID pParam)
 
{
 
CEdit *pEdit=(CEdit*)pParam;
 
pEdit->SetWindowText("");
 
critical_section.Lock();
 
// 锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
 
//直至执行 critical_section.Unlock();语句
 
for(int i=0;i<10;i++)
 
{
 
g_Array[i]=''D'';
 
pEdit->SetWindowText(g_Array);
 
Sleep(1000);
 
}
 
critical_section.Unlock();
 
return 0;
 
}
  • 分别双击按钮IDC_WRITEW和IDC_WRITED,添加其响应函数
 void CMultiThread8Dlg::OnWritew() 
 
{
 
CWinThread *pWriteW=AfxBeginThread(WriteW,
 
&m_ctrlW,
 
THREAD_PRIORITY_NORMAL,
 
0,
 
CREATE_SUSPENDED);
 
pWriteW->ResumeThread();
 
}
 
void CMultiThread8Dlg::OnWrited() 
 
{
 
CWinThread *pWriteD=AfxBeginThread(WriteD,
 
&m_ctrlD,
 
THREAD_PRIORITY_NORMAL,
 
0,
 
CREATE_SUSPENDED);
 
pWriteD->ResumeThread();
 
}

事件 CEvent

  • 事件状态有两种:有信号状态、无信号状态。
  • 事件有人工事件和自动事件。人工事件信号状态必须使用SetEvent手动切换为有信号状态。用ResetEvent切换为无信号状态。
  • 可以使用WaitForSingleObject设置线程同步。
  • 注意线程函数必须有返回值,否则创建线程时会出现参数错误。

CEvent.demo

  • 插入button和编辑框1,编辑框2,分别添加CEdit类型变量first,second。
  • 添加多线程管理头文件afxmt.h。
  • 创建CEvent对象 first。
  • 添加线程函数:
	UINT fun1(LPVOID lpParam){
	CEdit* x=(CEdit*)lpParam;
	CString str;
	for(int i=0;i<10;i++){
		str.Format(_T("%d"),i);
				Sleep(100);
		x->SetWindowText(str);
	}
	show.SetEvent();
	return 0;
	}

	UINT fun2(LPVOID lpParam){
	CEdit* x=(CEdit*)lpParam;
	CString str;
	WaitForSingleObject(show,INFINITE);
	for(int i=0;i<10;i++){
		str.Format(_T("%d"),i);
		Sleep(100);
		x->SetWindowText(str);
	}
	return 0;
}
  • 双击Button:
void ClabsdfaDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
	AfxBeginThread(fun1,&first);
	AfxBeginThread(fun2,&second);

}

互斥量 CMutex

  • CMutex和CCriticalSection类似。都可以在进程和线程之间进行通信,但是CCriticalSection在进程间通信时会消耗更多的资源。
  • 函数原型
    	HANDLE CreateMutex(
    		 LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针
    		 BOOL bInitialOwner, // 初始拥有者
    		 LPCTSTR lpName // 互斥对象名
    		);
    

    参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE,以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名,那么可以在本进程其他地方或是在其他进程通过OpenMutex()函数得到此互斥对象的句柄。

CMutex.demo

  • 插入button和编辑框1,编辑框2,分别添加CEdit类型变量first,second。

  • 添加多线程管理头文件afxmt.h。

  • 创建CMutex对象 :

    HANDLE handle=CreateMutex(NULL,FALSE,(LPCTSTR )"m");
    
  • 添加线程函数:

UINT fun1(LPVOID lpParam){
	CEdit* x=(CEdit*)lpParam;
	CString str;
	WaitForSingleObject(handle,INFINITE);

	for(int i=0;i<10;i++){
		str.Format(_T("%d"),i);
				Sleep(100);

		x->SetWindowText(str);
	}
	ReleaseMutex(handle);
	return 0;
}

UINT fun2(LPVOID lpParam){
	CEdit* x=(CEdit*)lpParam;
	CString str;
	WaitForSingleObject(handle,INFINITE);
	for(int i=0;i<10;i++){
		str.Format(_T("%d"),i);
		Sleep(100);
		x->SetWindowText(str);
	}
	ReleaseMutex(handle);

	return 0;
}
  • 双击Button:
void ClabsdfaDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
	AfxBeginThread(fun1,&first);
	AfxBeginThread(fun2,&second);

}

信号量 CSemaphore

  • CSemaphore可以限制变量可以被线程访问的数量。
  • 函数原型:
    	CSemaphore(LONG lInitialCount=1, 
    		LONG lMaxCount=1,	 
    		LPCTSTR pstrName=NULL,	 
    		LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);
    
  • 每有一个线程访问变量时,则计数值减一,当计数值为0时,其他访问该变量的线程被挂起。当某线程访问结束时,计数值会加1。

CSemaphore.demo

  • 建立一个基于对话框的工程,在对话框中加入一个按钮和三个编辑框控件。
  • 给编辑框添加变量:m_ctrlA、m_ctrlB和m_ctrlC;
  • 在文件开头添加:#include “afxmt.h”
  • 添加CSemaphore变量
    CSemaphore semaphoreWrite(2,2); 
    
  • 添加线程函数
UINT WriteA(LPVOID pParam)

{

	CEdit *pEdit=(CEdit*)pParam;
	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
	CString str;
	for(int i=0;i<10;i++)
	{
		str.Format(_T("%d"),i);
		pEdit->SetWindowText(str);
		Sleep(100);
	}

	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);

	return 0;

}
UINT WriteB(LPVOID pParam)

{

	CEdit *pEdit=(CEdit*)pParam;
	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
	CString str;

	for(int i=0;i<10;i++)

	{

		str.Format(_T("%d"),i);
		pEdit->SetWindowText(str);
		Sleep(100);

	}

	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);

	return 0;

}

UINT WriteC(LPVOID pParam)

{

	CEdit *pEdit=(CEdit*)pParam;


	WaitForSingleObject(semaphoreWrite.m_hObject,INFINITE);
	CString str;
	for(int i=0;i<10;i++)

	{

		str.Format(_T("%d"),i);
		pEdit->SetWindowText(str);
		Sleep(100);

	}

	ReleaseSemaphore(semaphoreWrite.m_hObject,1,NULL);

	return 0;

}
  • 双击Start按钮:
void CMultiThread10Dlg::OnBnClickedStart()
{
	// TODO: Add your control notification handler code here
	AfxBeginThread(WriteA,&m_ctrlA);
	AfxBeginThread(WriteB,&m_ctrlB);
	AfxBeginThread(WriteC,&m_ctrlC);
}

参考资料

MFC多线程各种线程用法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网狐6.6 服务器源代码&共享组件&数据库,包括服务器端所有组件(内核除外,现在市面上还没有6.6内核),共享组件(公共服务,界面控件,界面资源),以及全部数据库文件和脚本文件,6.6较6.5有较大改动,是学习研究的上等程序代码。 结合本人上次发布的客户端组件,即为网狐66系统模块全部源代码!!!官方售价几万,网上有人卖几百到几千不等,本程序绝对6.6新版代码(带道具),识货的下。 总共140M,7个解压包:1~7。 #ifndef KERNEL_ENGINE_HEAD_HEAD_FILE #define KERNEL_ENGINE_HEAD_HEAD_FILE ////////////////////////////////////////////////////////////////////////// //包含文件 #include #include #include #include #include //平台文件 #include "..\..\模板库\Template.h" #include "..\..\公共文件\Constant.h" #include "..\..\公共文件\GlobalDef.h" #include "..\..\共享组件\公共服务\ComService.h" ////////////////////////////////////////////////////////////////////////// //ADO 定义 #import "MSADO15.DLL" rename_namespace("ADOCG") rename("EOF","EndOfFile") using namespace ADOCG; typedef _com_error CComError; //COM 错误 typedef _variant_t CDBVarValue; //数据库数值 ////////////////////////////////////////////////////////////////////////// //导出定义 //导出定义 #ifndef KERNEL_ENGINE_CLASS #ifdef KERNEL_ENGINE_DLL #define KERNEL_ENGINE_CLASS _declspec(dllexport) #else #define KERNEL_ENGINE_CLASS _declspec(dllimport) #endif #endif //模块定义 #ifndef _DEBUG #define KERNEL_ENGINE_DLL_NAME TEXT("KernelEngine.dll") //组件 DLL 名字 #else #define KERNEL_ENGINE_DLL_NAME TEXT("KernelEngineD.dll") //组件 DLL 名字 #endif ////////////////////////////////////////////////////////////////////////// //系统常量 //常量定义 #define TIME_CELL 200 //时间单元 #define TIMES_INFINITY DWORD(-1) //无限次数 #define MAX_ASYNCHRONISM_DATA 8192 //异步数据 ////////////////////////////////////////////////////////////////////////// //网络定义 //连接错误 #define CONNECT_SUCCESS 0 //连接成功 #define CONNECT_FAILURE 1 //连接失败 #define CONNECT_EXCEPTION 2 //参数异常 //关闭原因 #define SHUT_REASON_INSIDE 0 //内部原因 #define SHUT_REASON_NORMAL 1 //正常关闭 #define SHUT_REASON_REMOTE 2 //远程关闭 #define SHUT_REASON_TIME_OUT 3 //网络超时

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值