如何在多线程程序中使用非确定性igraph函数?

时间:2015-10-21 18:22:28

标签: c multithreading igraph

我在多线程程序中使用igraph C库。每个线程使用igraph_barabasi_game创建随机图。虽然IGRAPH_THREAD_SAFE宏设置为1,但我仍然遇到明显与线程相关的崩溃。

这是一个演示问题的最小程序。我从两个线程调用do_work函数,它只是创建一个随机图。

#include <pthread.h>                                                         
#include <igraph/igraph.h>                                                   

void *do_work(void *arg)                                                     
{                                                                            
    igraph_t g;                                                                 
    igraph_barabasi_game(&g, 100, 1, 4, NULL, 0, 1, 0, IGRAPH_BARABASI_PSUMTREE, NULL);
    igraph_destroy(&g);                                                      
}                                                                            

pthread_t threads[2];                                                        

int main (void)                                                              
{                                                                               
#if IGRAPH_THREAD_SAFE == 0                                                  
    fprintf(stderr, "igraph is not thread safe\n");                             
    return 1;                                                                   
#endif                                                                          

    pthread_create(&threads[0], NULL, do_work, NULL);                           
    pthread_create(&threads[1], NULL, do_work, NULL);                           
    pthread_join(threads[0], NULL);                                             
    pthread_join(threads[1], NULL);                                             

    return 0;                                                                   
}

可以使用gcc test.c -ligraph -lpthread进行编译。这个特定的程序不会崩溃,但是当我通过helgrind运行时,会出现与随机数生成器相关的错误。

==20144== Possible data race during write of size 8 at 0x547D038 by thread #3
==20144== Locks held: none                                                      
==20144==    at 0x4F172A5: igraph_rng_mt19937_get (random.c:354)                
    ==20144==    by 0x4F17358: igraph_rng_mt19937_get_real (random.c:381)       
    ==20144==    by 0x4F17951: igraph_rng_get_unif (random.c:805)               
    ==20144==    by 0x4ED3F68: igraph_i_barabasi_game_psumtree (games.c:381) 
    ==20144==    by 0x400828: do_work (in /home/rmcclosk/test/a.out)            
    ==20144==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    ==20144==    by 0x5488181: start_thread (pthread_create.c:312)              
    ==20144==    by 0x579847C: clone (clone.S:111)                              
    ==20144==                                                                   
    ==20144== This conflicts with a previous write of size 8 by thread #2       
    ==20144== Locks held: none                                                  
    ==20144==    at 0x4F17400: igraph_rng_mt19937_seed (string3.h:84)           
    ==20144==    by 0x4F177F1: igraph_rng_seed (random.c:684)                   
    ==20144==    by 0x4ED4354: igraph_i_barabasi_game_psumtree (games.c:340) 
    ==20144==    by 0x400828: do_work (in /home/rmcclosk/test/a.out)            
    ==20144==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    ==20144==    by 0x5488181: start_thread (pthread_create.c:312)              
    ==20144==    by 0x579847C: clone (clone.S:111)

我认为解决方案是将不同的随机数生成器对象传递给每个线程,但我没有看到这样做的方法,因为igraph_barabasi_game不将生成器作为参数。有没有一种在多线程程序中使用这些非确定性函数的正确方法?

1 个答案:

答案 0 :(得分:0)

这还不是一个真正的答案,但是评论太长了所以我将其作为答案发布

igraph仍然无法保证线程安全性,尽管有些努力试图用线程本地替换全局变量。 (这就是IGRAPH_THREAD_SAFE宏的作用)。

在内部,非确定性igraph函数需要RNG调用RNG_BEGIN()宏来表示他们使用RNG的意图(然后调用RNG_END()来表示他们不需要任何RNG更多)。 RNG_BEGIN()调用igraph_rng_default()来获取“默认”随机数生成器(如果这是第一次使用RNG,也会播种它)。 helgrind确定的竞争条件可能表示同时由两个线程播种RNG。有趣的是,igraph_rng_default()返回线程局部结构的地址(igraph_i_rng_default,请参见源代码中的src/random.c),此线程局部结构包含一个存储RNG是否存在的标志已经播种或播种。另一方面,RNG的状态似乎在线程之间共享,所以可能发生的是两个或更多线程试图弄乱相同的状态向量 RNG,因为所有线程都有自己的线程局部标志,表示RNG是否被播种。

如果我的预感是正确的,那么RNG的问题可以通过修补src/random.c并通过在其声明中添加igraph_i_rng_default_state使IGRAPH_THREAD_LOCAL线程本地来解决。无论哪种方式,这绝对是当前版本的igraph中的一个错误,所以你应该在Github上file an issue