【问题标题】:Multithreading returns an unhandled exception for storing information多线程返回存储信息的未处理异常
【发布时间】:2015-12-30 13:45:41
【问题描述】:

我会尽可能清楚地解释我的问题。我有一个必须处理的多线程框架。这是一个路径跟踪器渲染器。当我尝试存储我的线程提供的一些信息时,它给了我错误。尽量避免发布所有代码,我将逐步解释我的意思:

我的 TileTracer 类是一个线程

class TileTracer : public Thread{
...
}

而且我有一定数量的线程:

#define MAXTHREADS      32
TileTracer* worker[MAXTHREADS];

工作线程的数量在下面的初始化代码中设置,线程也被启动:

void Renderer::Init(){
    accumulator = (vec3*)MALLOC64(sizeof(vec3)* SCRWIDTH * SCRHEIGHT);
    memset(accumulator, 0, SCRWIDTH * SCRHEIGHT * sizeof(vec3));
    SYSTEM_INFO systeminfo;
    GetSystemInfo(&systeminfo);
    int cores = systeminfo.dwNumberOfProcessors;
    workerCount = MIN(MAXTHREADS, cores);
    for (int i = 0; i < workerCount; i++)
    {
        goSignal[i] = CreateEvent(NULL, FALSE, FALSE, 0);
        doneSignal[i] = CreateEvent(NULL, FALSE, FALSE, 0);
    }
    // create and start worker threads
    for (int i = 0; i < workerCount; i++)
    {
         worker[i] = new TileTracer();
         worker[i]->init(accumulator, i);
         worker[i]->start(); //start the thread
    }
    samples = 0;
}

我的线程的 init() 方法在我的标题中简单地定义如下:

void init(vec3* target, int idx) { accumulator = target, threadIdx = idx; }

而 start() 是:

void Thread::start() 
{
     DWORD tid = 0; 
     m_hThread = (unsigned long*)CreateThread( NULL, 0,    (LPTHREAD_START_ROUTINE)sthread_proc, (Thread*)this, 0, &tid );
     setPriority( Thread::P_NORMAL );
 }

不知何故(我不知道具体在哪里),每个线程都会调用以下 main 方法,该方法旨在定义像素的颜色(您不必全部了解):

vec3 TileTracer::Sample(vec3 O, vec3 D, int depth){
  vec3 color(0, 0, 0);
  // trace path extension ray
  float t = 1000.0f, u, v;
  Triangle* tri = 0;
  Scene::mbvh->pool4[0].TraceEmbree(O, D, t, u, v, tri, false);
  totalRays++;
  // handle intersection, if any
  if (tri)
  {
    // determine material color at intersection point
    Material* mat = Scene::matList[tri->material];
    Texture* tex = mat->GetTexture();
    vec3 diffuse;
    if (tex)
    {
        ...
    }
    else diffuse = mat->GetColor();
    vec3 I = O + t * D; //we get exactly to the intersection point on the object

    //we need to store the info of each bounce of the basePath for the offsetPaths
    basePath baseInfo = { O, D, I, tri };
    basePathHits.push_back(baseInfo);

    vec3 L = vec3(-1 + Rand(2.0f), 20, 9 + Rand(2.0f)) - I; //(-1,20,9) is Hard-code of the light position, and I add Rand(2.0f) on X and Z axis
    //so that I have an area light instead of a point light
    float dist = length(L) * 0.99f; //if I cast a ray towards the light source I don't want to hit the source point or the light source
    //otherwise it counts as a shadow even if there is not. So I make the ray a bit shorter by multiplying it for 0.99
    L = normalize(L);
    float ndotl = dot(tri->N, L);
    if (ndotl > 0)
    {
        Triangle* tri = 0;
        totalRays++;
        Scene::mbvh->pool4[0].TraceEmbree(I + L * EPSILON, L, dist, u, v, tri, true);//it just calculates the distance by throwing a ray
        //I am just interested in understanding if I hit something or not
        //if I don't hit anything I calculate the light transport (diffuse * ndotL * lightBrightness * 1/dist^2
        if (!tri) color += diffuse * ndotl * vec3(1000.0f, 1000.0f, 850.0f) * (1.0f / (dist * dist));
    }
    // continue random walk since it is a path tracer (we do it only if we have less than 20 bounces)
    if (depth < 20)
    {
        // russian roulette
        float Psurvival = CLAMP((diffuse.r + diffuse.g + diffuse.b) * 0.33333f, 0.2f, 0.8f);
        if (Rand(1.0f) < Psurvival)
        {
            vec3 R = DiffuseReflectionCosineWeighted(tri->N);//there is weight
            color += diffuse * Sample(I + R * EPSILON, R, depth + 1) * (1.0f / Psurvival);
        }
    }
  }
  return color;
}

现在,您不必完全理解整个代码,因为我的问题如下:如果您注意到,在最后一种方法中有以下 2 行代码:

basePath baseInfo = { O, D, I, tri };
basePathHits.push_back(baseInfo);

我只是创建了一个简单的结构“basePath”,定义如下:

struct basePath
{
    vec3 O, D, hit;
    Triangle* tri;
};

我将它存储在我的代码开头定义的结构向量中:

vector<basePath> basePathHits;

问题是这似乎带来了异常。事实上,如果我尝试存储这些信息,我稍后需要在我的代码中,程序崩溃给我一个异常:

Template.exe 中 0x0FD4FAC1 (msvcr120d.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0x3F4C1BC1。

其他时候,不做任何改变,错误是不同的,它是以下一个:

虽然不存储这些信息,但一切正常。同样,如果我将核心数设置为 1,一切正常。那么,为什么多线程不允许我这样做呢?如果这些还不够,请随时询问更多信息。

【问题讨论】:

  • 您是否尝试按“重试”并进入调试器? 在您的代码中 发生崩溃的位置是什么?你检查过所有相关变量的值吗?
  • basePathHits 是在所有线程之间共享,还是每个线程都有自己的版本?如果它是共享的,你是否在尝试push_back 之前同步访问它(它看起来不像你)?

标签: c++ multithreading exception-handling


【解决方案1】:

尝试对您的代码进行以下更改:

//we need to store the info of each bounce of the basePath for the offsetPaths
basePath baseInfo = { O, D, I, tri }; 
static std::mutex myMutex;
myMutex.lock();
basePathHits.push_back(baseInfo);
myMutex.unlock();

如果这消除了异常,那么问题是对basePathHits 的非同步访问(即多个线程同时调用push_back)。您需要仔细考虑最好的解决方案是什么,以尽量减少同步对性能的影响。

【讨论】:

  • 不幸的是,它并没有解决异常。我明白你的意思是使用互斥锁,因为这是我第一次处理多线程,所以我没有考虑这个问题。但不幸的是不能解决问题
  • 参考您的原始帖子,“虽然不存储这些信息,但一切正常” - 您的意思是说,如果您删除 push_back 行,您不再看到这些异常?
  • 一切似乎都指向我的原始诊断,所以我无法弄清楚为什么mutex 不能解决问题...您的代码中是否还有其他部分可以修改basePathHits?
  • 不,没有,已经找到了..这是我修改 basePathHits 的唯一部分。我正在尝试提出另一种解决方案:如果不将 basePathHits 作为全局变量,该怎么办?我将其设为本地,以便每个线程都有自己的 basePathHits?它应该工作,对吧?怎么做?在每个线程使用的特定方法中声明该变量就足够了?
  • 我会将basePathHits 设为TileTracer 类的成员变量,这样每个线程都会写入自己的版本。
【解决方案2】:

可能我没看到,但没有保护目标 - 没有互斥体或原子。据我所知,std::vector 在多线程中需要这个。

【讨论】:

    猜你喜欢
    • 2021-06-29
    • 1970-01-01
    • 2014-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多