cmultithreadingpthreadsraytracingpthread-join

Multi threading Raytracer


I am making a raytracer, im trying to use pthread to divide the rendering. i noticed that isnt helping with the speed because the function pthread_join is to slow, if i use a loop to make the 'await' is way faster and works almost every time fine. But i cant use that because the time of rendering changes with the scene. Is there a way to check if a thread is finished, on a more efficient way. This is the code. `

int threats(t_file *c) //this function creates the threads
{
    int i;
    int err;

    pthread_t th[THREADS];
    i = 0;
    printf("1\n");
    c->thread = -1;
    mlx_clear_window(c->mlx_ptr, c->win_ptr);
    while (i < THREADS)
    {
        err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)c);
        if (err)
            return parse_error("Thread Error: CAN NOT CREATE THREAD");
        i++;
    }
    
    // while (i-- >= 0)
    //  pthread_join(th[i], 0);

    //my await function xd
    while (i < 200000000)
        i++;
    mlx_put_image_to_window(c->mlx_ptr, c->win_ptr, c->img.mlx_img, 0, 0);

    c->thread = 0;
    return 1;
}

void paint_scene(void *a)

{

    int y;
    int x;
    t_ray ray;
    int color;
    t_file *c;

    c = (t_file *)a;
    color = 0;
    c->thread++;
    y = (c->thread * (c->win_heigth / THREADS));
    printf("y:%d,hilo%d\n", y, c->thread);
    while (y < (c->thread + 1) * (c->win_heigth / THREADS))
    {
        x = 0;
        while (x < c->win_width)
        {
            ray = generate_ray(x, y, *c);
            color = get_intersections(&ray, c);
            if (c->ligth)
                color = shading(&ray, color, c);
            my_mlx_pixel_put(&c->img, x, y, color);
            x++;
        }
        //ft_printf("\rLoading%d: %d%%", c->thread, y / (c->win_heigth / 100));
        y++;
    }
    pthread_exit(0);
}
`

Solution

  • You have a concurrency problem here in your thread function:

    c->thread++;
    y = (c->thread * (c->win_heigth / THREADS));
    printf("y:%d,hilo%d\n", y, c->thread);
    while (y < (c->thread + 1) * (c->win_heigth / THREADS)) 
    {
      ....
    }
    

    c->thread is shared between all threads, and based on likely thread timings and current face of the moon, I can make an educated guess and say that the first thread is calculating the whole image. When starting up, the first thread might see c->thread == -1, but later (if thread startup is faster than the while loop) other thread increase the value until the first thread sees c->thread == THREADS-1

    To fix this, each call to create_thread must pass a pointer to a unique parameter object that holds that threads id. So remove the thread member from t_file. It probably serves no purpose there. And create a type of struct that holds the parameters to the thread function:

    struct thread_param
    {
         unsigned int thread;
         file_t *c;
    }
    

    You use it like this when starting threads:

    struct thread_param params[THREADS];
    while (i < THREADS)
    {
        params[i].thread = i;
        params[i].c = c;
       
        err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)&(params[i]));
        if (err)
            return parse_error("Thread Error: CAN NOT CREATE THREAD");
        i++;
    }
    

    And you access the data in your thread function:

    void paint_scene(void *a)
    {
      struct thread_param *param = (struct thread_param *)a;
      unsigned int thread = param->thread;
      t_file *c = param->c;
    
       /* 
         in the rest of the code you remove `c->thread++` 
         and replace `c->thread` with `thread`
       */
       ....
    }