c++多线程同步(1)

技术博客 (147) 2023-09-16 16:24:01

此篇讨论一下c++中的线程同步。

线程同步方式:

    临界区

    事件

    互斥量

   信号量

为什么要线程同步?

       从之前的讨论及实际的项目中,可以看到线程同步给我们带来了很多便利性,但是多线程也同时给我们带来了很多麻烦:一方面,在开发调试阶段带来了很大的难度;另一方面,则需要考虑资源访问的一致性原则。因为在程序中使用多线程的时候,每一个线程并不会各行各事,每个线程之间必然会存在一些联系。如果两个或者多个线程访问同一个独占性的系统资源,这样会导致系统错误。

下面对实现线程同步的几种方法分别介绍

(1) 临界区

临界区是一段独占对某些共享资源的访问代码,在任意时刻只允许一个线程对共享资源访问。如果有多个线程试图同时访问临界区,那么只有一个线程进入临界区,其他试图访问临界区的线程将被挂起,并一直持续到进入临界区的线程离开,其他线程可以继续抢占临界区。

       需要说明的是,在使用临界区时,一般不允许其运行时间过长,因为只要进入临界区的线程不离开,其他视图进入此临界区的线程都会挂起,进入等待状态,因此这样在一定程度上影响程序的性能。因此,不要使临界区一直处于未释放的状态。

     还需要注意的是,虽然临界区同步速度比较快,但是只能用来同步本进程内的线程,而不能跨进程同步

     MFC中,有一个CCriticalSection类,此类中有两个方法Lock和UnLock,只需要在需要同步的代码前后假如这两个函数,就可以实现临界区资源。

     例子如下(部分代码):

   

CCriticalSection critical_section;
char g_array[10];

UINT WriteW(LPVOID pParam)
{
	CEdit *pEdit = (CEdit *)pParam;
	pEdit->SetWindowText(" ");
	critical_section.Lock();//锁定临界区

	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();
	
	for (int i=0; i<10; i++)
	{
		g_array[i]='D';
		pEdit->SetWindowText(g_array);
		Sleep(1000);
	}
	critical_section.Unlock();
	return 0;

}

创建线程:

void CMthread8Dlg::OnWritew() 
{
	// TODO: Add your control notification handler code here
	CWinThread *pWriteW = AfxBeginThread((AFX_THREADPROC)WriteW,
										&m_ctrW,
										THREAD_PRIORITY_NORMAL,
										0,
										CREATE_SUSPENDED);
	pWriteW->ResumeThread();
}

void CMthread8Dlg::OnWrited() 
{
	// TODO: Add your control notification handler code here
	CWinThread *pWriteD = AfxBeginThread((AFX_THREADPROC)WriteD,
										&m_ctrD,
										THREAD_PRIORITY_NORMAL,
										0,
										CREATE_SUSPENDED);
	pWriteD->ResumeThread();
}

执行结果:

c++多线程同步(1) (https://mushiming.com/) 技术博客 第1张

从执行结果看,读的线程只能等到写的线程从临界区出来后才能访问临界区。

(2) 事件

  实例参见本博客:c++CreateEvent函数在多线程中使用及实例
  此实例中采用CreateEvent 事件函数实现多线程同步的。

  也可以采用MFC中的CEvent类实现多线程同步。   

部分代码如下:

CEvent event;
char g_array[10];

UINT WriteW(LPVOID pParam)
{
	CEdit *pEdit = (CEdit *)pParam;
	pEdit->SetWindowText(" ");

	for (int i=0; i<10; i++)
	{
		g_array[i] = 'W';
		pEdit->SetWindowText(g_array);
		Sleep(200);
	}
	event.SetEvent();
	return 0;
}	
UINT WriteD(LPVOID pParam)
{
	CEdit *pEdit = (CEdit *)pParam;
	pEdit->SetWindowText(" ");
	WaitForSingleObject(event,INFINITE);
	for (int i=0; i<10; i++)
	{
		g_array[i] = 'W';
		pEdit->SetWindowText(g_array);
		Sleep(200);
	}
	return 0;
}

创建线程的代码和临界区中显示的代码一样。

主要通过WaitForSingleObject函数实现多线程的同步。此函数等待上一个线程释放事件,即事件变成有信号状态时,才执行此线程下面的程序。

THE END

发表回复