c++多线程问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++多线程问题相关的知识,希望对你有一定的参考价值。

临界区具体是怎么控制多个线程同步的?

  当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。

CCriticalSection类的用法非常简单,步骤如下:
 

定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如CCriticalSection critical_section;
在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()获得临界区对象: critical_section.Lock();

在线程中调用该函数来使线程获得它所请求的临界区。如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。
访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:critical_section.Unlock();

再通俗一点讲,就是线程A执行到critical_section.Lock();语句时,如果其它线程(B)正在执行critical_section.Lock();语句后且critical_section. Unlock();语句前的语句时,线程A就会等待,直到线程B执行完critical_section. Unlock();语句,线程A才会继续执行。
参考技术A 临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。

下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作,用临界区结构对象g_cs来保持线程的同步,并在开启线程前对其进行初始化。为了使实验效果更加明显,体现出临界区的作用,在线程函数对共享资源g_cArray[10]的写入时,以Sleep()函数延迟1毫秒,使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护,则共享资源数据将被破坏,而使用临界区对线程保持同步后则可以得到正确的结果。代码实现清单附下:

// 临界区结构对象
CRITICAL_SECTION g_cs;
// 共享资源
char g_cArray[10];
UINT ThreadProc10(LPVOID pParam)

 // 进入临界区
 EnterCriticalSection(&g_cs);
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 
  g_cArray[i] = ''a'';
  Sleep(1);
 
 // 离开临界区
 LeaveCriticalSection(&g_cs);
 return 0;

UINT ThreadProc11(LPVOID pParam)

 // 进入临界区
 EnterCriticalSection(&g_cs);
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 
  g_cArray[10 - i - 1] = ''b'';
  Sleep(1);
 
 // 离开临界区
 LeaveCriticalSection(&g_cs);
 return 0;

……
void CSample08View::OnCriticalSection()

 // 初始化临界区
 InitializeCriticalSection(&g_cs);
 // 启动线程
 AfxBeginThread(ThreadProc10, NULL);
 AfxBeginThread(ThreadProc11, NULL);
 // 等待计算完毕
 Sleep(300);
 // 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);


  在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响。程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放,同样也会引起其他线程的长时间等待。换句话说,在执行了EnterCriticalSection()语句进入临界区后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection()语句的执行。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

  MFC为临界区提供有一个CCriticalSection类,使用该类进行线程同步处理是非常简单的,只需在线程函数中用CCriticalSection类成员函数Lock()和UnLock()标定出被保护代码片段即可。对于上述代码,可通过CCriticalSection类将其改写如下:

// MFC临界区类对象
CCriticalSection g_clsCriticalSection;
// 共享资源
char g_cArray[10];
UINT ThreadProc20(LPVOID pParam)

 // 进入临界区
 g_clsCriticalSection.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 
  g_cArray[i] = ''a'';
  Sleep(1);
 
 // 离开临界区
 g_clsCriticalSection.Unlock();
 return 0;

UINT ThreadProc21(LPVOID pParam)

 // 进入临界区
 g_clsCriticalSection.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 
  g_cArray[10 - i - 1] = ''b'';
  Sleep(1);
 
 // 离开临界区
 g_clsCriticalSection.Unlock();
 return 0;

……
void CSample08View::OnCriticalSectionMfc()

 // 启动线程
 AfxBeginThread(ThreadProc20, NULL);
 AfxBeginThread(ThreadProc21, NULL);
 // 等待计算完毕
 Sleep(300);
 // 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
参考技术B 进程中的所有线程共享进程的虚拟地址空间,进程中的线程是并行执行的,系统为每个线程划分执行时间, 参考技术C 看下咱那个操作系统的书,上边哟了

以上是关于c++多线程问题的主要内容,如果未能解决你的问题,请参考以下文章

C++多线程怎么实现

c++多线程问题

c++ 多线程与c多线程有啥区别?

纯 C++ 中的多线程?

C++多线程编程

C++ 多线程 操作List 的问题