现在的位置: 首页 > 综合 > 正文

new线程是否安全

2019年01月13日 ⁄ 综合 ⁄ 共 1855字 ⁄ 字号 评论关闭

首先声明,此帖为错误帖,希望大家能作为反例来看。

希望大家能指正

当时,就是因为加入的是单线程运行时库,导致new和delete操作出错。后来,在看书的过程中,才知道,windows中,堆是属于进程的,当多个线程对堆进行操作时,是需要加锁的,如果导入的是多线程运行时库,那么,在new和delete时,是加锁来操作的。以后,我将向大家介绍windows的内存管理机制。

 

这段时间正在做一个模块,总是出错,提示指令引用的内存不能为“read”或“written”。

逐个排查错误,最终,发现是线程处理函数中的new语句那里出了问题。

那么,平时我们如下所用是安全的么?

int *p = new int:

在单线程程序中,这样用是安全的。多线程中呢?

you know,堆内存是多线程共用的。如果两个线程同时对堆内存发出请求,问题就出现了。

你可以进行如下实验:

#include <stdio.h>
#include <windows.h>

DWORD WINAPI ThrdProc(LPVOID lpParam);
int main()
{
  int i=0;
  HANDLE hThrd[8];
  for(i=0; i<8; i++)
  {
    hThrd[i] = CreateThread(NULL, 0, ThrdProc, 0, NULL, 0);
  }
 
  for(i=0; i<8; i++)
  {
    WaitForSingleObject(hThrd[i], INFINITE);
    CloseHandle(hThrd[i]);
  }
 printf("ok!\n");
  return 0;
}

DWORD WINAPI ThrdProc(LPVOID lpParam)
{
 int *pi = NULL;
 for(int i=0; i<1000; i++)
 { 
  pi = new int;
  if(NULL != pi)
  {
   delete pi;
   pi = NULL;
  }
 }
 return 0;
}

此实验中,8个线程频繁申请堆空间

接着,你可以再做一个实验

在上个实验代码中,delete pi;语句前,加一句printf("%d\n",*pi);,然后再运行一下,结果怎样呢?

现在可以总结了:

如果多个线程同时请求堆内存操作,则会引发错误,因为线程共用堆内存。因此,第一个实验中,线程频繁操作堆内存,引起冲突,导致错误出现。

那么,平时我们直接用new等操作,为什么不会出错误呢?你要知道,堆内存的分配及回收,速度是相当快的。在第二个实验中,线程不仅请求堆内存操作,还加了一个printf。与new的执行速度相比,printf慢多了。这样,就大大降低了冲突(线程对堆内存操作)概率。因此,第二个实验运行时极少出错,但不是绝对的安全。我们平时写多线程的代码,也正因为是这样,所以,虽然存在隐患,但是却很少发现它。

解决这个隐患,可以给堆内存加个全局排斥锁,或者临界,只要线程对堆内存的操作(如new、delete,malloc、free),就要申请下

下面是用临界做的测试:

#include <windows.h>
#include <iostream.h>

CRITICAL_SECTION g_lijie;

DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
 for(int i=0; i<1000; i++)
 {
  EnterCriticalSection(&g_lijie);
  int *p = new int[10];
  LeaveCriticalSection(&g_lijie);
  if (p != NULL)
  {
   i++;
   //cout<<p<<endl;
   EnterCriticalSection(&g_lijie);
   delete[] p;
   LeaveCriticalSection(&g_lijie);
  }
  
 }
 return 1;
}

void main()
{
 HANDLE hThread;

 InitializeCriticalSection(&g_lijie);

 for (int i=0; i<10; i++)
 {
  hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,NULL);
 }

 Sleep(100);
}

CRITICAL_SECTION,InitializeCriticalSection,EnterCriticalSection,LeaveCriticalSection,这些是临界区的操作,如果不明白,可以msdn下

抱歉!评论已关闭.