C++ 使用两种不同算法生成工件的多线程光线跟踪器

C++ 使用两种不同算法生成工件的多线程光线跟踪器,c++,multithreading,graphics,3d,raytracing,C++,Multithreading,Graphics,3d,Raytracing,我一直在尝试用我的光线跟踪器实现多线程,但我正在试验与MT相关的奇怪工件。现在我确信这与算法无关,因为它发生在两种不同的方法中 下面是MT算法的情况,其中第一个线程负责图像的下半部分,另一个线程负责图像的上半部分。在第一种情况下,我在执行任何操作之前发送thread0返回,在第二种情况下,thread1返回 按预期工作。现在,两个线程一起工作: 让我们转到第二个算法,它采用逐像素的方法,线程0->pixel0,线程1->pixel1,线程0->pixel2,线程0->pixel3 第一个图

我一直在尝试用我的光线跟踪器实现多线程,但我正在试验与MT相关的奇怪工件。现在我确信这与算法无关,因为它发生在两种不同的方法中

下面是MT算法的情况,其中第一个线程负责图像的下半部分,另一个线程负责图像的上半部分。在第一种情况下,我在执行任何操作之前发送thread0返回,在第二种情况下,thread1返回

按预期工作。现在,两个线程一起工作:

让我们转到第二个算法,它采用逐像素的方法,线程0->pixel0,线程1->pixel1,线程0->pixel2,线程0->pixel3

第一个图像是仅thread0工作时的图像,第二个图像是仅thread1工作时的图像:

再一次,它按照预期工作,由于只有一个线程在工作,因此出现了清晰、强烈的黑行(从在线托管中可能看不到,但从离线图像查看器中很容易看到)

现在,双方共同努力:

和以前很相似

运行该程序时,我能够识别出某些像素的计算似乎不止一次:看看这个控制台输出:

只应打印其中一个,如ST案例。更奇怪的是,这是随机的。如果我在其他时间运行MT版本,这种重复可能会消失,但会在另一个屏幕上显示。 重复这些打印信息时,其他信息也会有所不同:

>

我想听听你的建议,看看到底发生了什么。 如果有人对代码感兴趣: 一些代码(实施像素交替算法所需的更改):

void RayTracer::draw\u多线程(图像*图像,场景*场景,int线程\u id){
int ctr=0;//用于写入颜色值的数组的初始位置
int initial_x=0;//初始像素
如果(线程id==1){
初始_x=1;
ctr=1;
}
if(thread_id==0)//每次测试一个线程
返回;
对于(int y=0;ygetHeight();y++){
//浮动px=px________________;;
//py=py+ystep;
对于(int x=initial_x;xgetWidth();x+=2){/+2,在线程之间交替像素
....
....
....
b[ctr]=min(蓝色*255.0f,255.0f);//每种颜色的单独数组决定暂时使用三个,以便于MT实现
c[ctr]=最小值(绿色*255.0f,255.0f);
d[ctr]=最小值(红色*255.0f,255.0f);
ctr+=2;//由于MT,增加了两个
}
}
pthread_exit(NULL);
其他一些代码(实现每个线程算法的半屏幕所需的更改):

void光线跟踪器::绘制多线程2(图像*图像,场景*场景,int线程id){
float inv_div=0.5;//控制每个线程的工作量
int ctr=0;//线程0从
int y=0;//同上
int initial_x=0;
如果(线程id==1){

你以前写过多少多线程代码?我很好奇你是否知道单线程函数在多线程环境中正常工作需要改变的方式。你在什么体系结构上运行这个?太多的外来代码无法通过。你的线程有单独的数据副本还是共享一些?我下一个赌注是你如果没有正确的锁或使用非线程安全API,UR共享是错误的。尝试为每个线程单独复制所有的文件,如果工作切换一次共享一个变量,找出哪一个问题。在所有线程完成之后,还构造最终图像…Drew Dormann。我不说,除非您考虑WRITI。将具有两个线程的单个数组视为有意义的东西。Mike Vine:x86-64
BOTO x: 403 y 405 thread_id: 1

BOTO x: 403 y 405 thread_id: 1

BOTO x: 403 y 405 thread_id: 1

BOTO x: 403 y 405 thread_id: 1
 normal.x: 0 normal.y: 0 normal.z: -1.06 x: 400 y 409 thread_id: 0
intersection.x : -275.817 intersection.y: 61.5662 intersection.z: 283.019 
x: 400 y 409 thread_id: 0
green: 0 x: 400 y 409    
BOTO x: 400 y 409 thread_id: 0 
blue: 0 x: 400 y 409 
normal.x: 0 normal.y: 0 normal.z: -1.06 x: 400 y 409 thread_id: 0
intersection.x : -330.647 intersection.y: 73.8051 intersection.z: -283.019  
x: 400 y 409 thread_id: 0
green: 1.23263 x: 400 y 409
blue: 1.86762 x: 400 y 409
BOTO x: 400 y 409 thread_id: 0 
normal.x: 0 normal.y: 0 normal.z: 1.06 x: 400 y 409 thread_id: 0
intersection.x : -374.61 intersection.y: 83.6182 intersection.z: 283.019  
x: 400 y 409 thread_id: 0
green: 1.36558 x: 400 y 409
blue: 2.06906 x: 400 y 409
BOTO x: 400 y 409 thread_id: 0
normal.x: 0 normal.y: 0 normal.z: -1.06 x: 400 y 409 thread_id: 0
intersection.x : -409.859 intersection.y: 91.4863 intersection.z: -283.019 x: 400 y 409 thread_id: 0
x: 400 y 409 thread_id: 0
green: 1.36558 x: 400 y 409
blue: 2.06906 x: 400 y 409
BOTO x: 400 y 409 thread_id: 0
void RayTracer::draw_multithread (Image *image, Scene *scene, int thread_id) {
  int ctr=0; //initial position of the array to write the color values
  int initial_x=0; //initial pixel
  if (thread_id==1) {
    initial_x=1;
    ctr=1;
  }

  if (thread_id==0) //to test one thread each time
    return;        

  for (int y=0; y<image->getHeight(); y++) {
    //float px = px_inicial;
    //py = py + ystep;
    for (int x=initial_x; x<image->getWidth(); x+=2) { //+2 to alternate the pixels between threads
      ....
      ....
      ....
      b [ctr] = min (blue*255.0f,255.0f); //separate arrays for each color decided to use three temporarily to easy the MT implementation
      c [ctr] = min (green*255.0f,255.0f);
      d [ctr] = min (red*255.0f,255.0f);
      ctr+=2;   //increment in two due to MT
    }
  }
pthread_exit (NULL);    
void RayTracer::draw_multithread2 (Image *image, Scene *scene, int thread_id) {
   float inv_div=0.5; //control how much work is made by each thread
   int ctr=0; //thread 0 starts on the beggining
   int y=0;   //same as above
   int initial_x=0;
   if (thread_id==1) {
     cout << "thread_1" << endl;
     ctr=1024*384; //thread 1 starts on the half
     y=384; // same as above
     inv_div=1; //necessary for thrad1 to do half of the rendering
   }

   if (thread_id==0)
      return;

   for (; y<(float)image->getHeight()*inv_div; y++) { //increment in one
     //float px = px_inicial;
     //py = py + ystep;
     for (int x=initial_x; x<image->getWidth(); x++) {
     b [ctr] = min (blue*255.0f,255.0f);
     c [ctr] = min (green*255.0f,255.0f);
     d [ctr] = min (red*255.0f,255.0f);
     ctr++; // also increments in one pixel each iteration
   }
 }
 pthread_exit (NULL);
 pthread_t threads [2];
 thread_data td_array [2]; //for being able to throw the MT methods on class
 void *status;
 TGAManager tgaManager ("z.tga",true);
 if (tgaManager.isFileOpen()) {
   tgaManager.writeHeadersData (image);
   RayTracer rt (image.getHeight() * image.getWidth(),1);
   int rc;
   for (int i=0; i<2; i++) {
     //cout << "main() : creating thread, " << i << endl;
     td_array[i].thread_id=i; //thread identification to make possible the methods working differently according with the calling thread
     td_array[i].rt_ptr = &rt; //to pass the same RayTracer instancy to each method, since the array where the pixels colors are written is there
     td_array[i].img_ptr = &image;
     td_array[i].scene_ptr = &scene;
     //cout << "td_array.thread_index: " << td_array[i].thread_id << endl;
     rc = pthread_create (&threads[i], NULL, RayTracer::run_thread, &td_array[i]);
  }
  if (rc) {
     cout << "Error:unable to create thread," << rc << endl;
     exit(-1);
  }
  for (int i=0; i<2; i++ ) {
     rc = pthread_join(threads[i], &status);
     if (rc) {
        cout << "Error:unable to join," << rc << endl;
        exit(-1);
     }
  }


struct thread_data { // struct to pass all the required information for being able to let the MT methods on the RayTracer class
  int thread_id;
  RayTracer* rt_ptr;
  Image* img_ptr;
  Scene* scene_ptr;
};   

static void* run_thread (void* ptr) { //calls the real multithreading method draw_multithread2 or draw_multithread 
     cout << "run_thread..." << endl;
     void *nullptr;
     thread_data* td = static_cast <thread_data*> (ptr);
     td->rt_ptr->draw_multithread2 (td->img_ptr,td->scene_ptr,td->thread_id);
     //td->rt_ptr->draw (td->img_ptr,td->scene_ptr);
     return nullptr;
     cout << "" << endl;
  }