当join() - 线程时,C ++程序有时会崩溃

时间:2018-04-24 01:59:09

标签: c++ multithreading c++11 concurrency

下面是一个示例,但这里是整个代码https://github.com/szlavalle/TFG

编辑:我已将原因缩小到 thread_local变量 thread_index向量,即thread_local。如果我删除该向量上的thread_local限定符,程序不会崩溃。 Visual Leak Detector(无法在Windows上使用valgrind)不会报告任何内存泄漏。

由于标题仍然存在,下面的程序大约有75%的时间崩溃。这是一大堆代码,但你可以忽略我认为的大部分代码。问题出在execute()结尾的join循环中。出于某种原因,它在大约75%的时间在控制台上运行时崩溃了。但是,从不在Visual Studio上崩溃。这是某种Windows问题吗?编译器标志还是什么?

奇怪的是,如果我断开()而不是join()线程,程序不会崩溃,但这不是我想要的。看一个线程是否可连接()也没有解决它。

using namespace std;

// These are all the thread_local variables

thread_local auto rng = default_random_engine{};
thread_local std::random_device rd;
thread_local std::mt19937 re(rd());    

thread_local int Duct::total_population = 0;
thread_local int Duct::dysfunctional_population = 0;
thread_local int Duct::total_reproductions = 0;
thread_local int Duct::dysfunctional_reproductions = 0;

thread_local int Duct::stem_counter = 0;
thread_local int Duct::bipotent_counter = 0;
thread_local int Duct::proglumepi_counter = 0;
thread_local int Duct::lumepi_counter = 0;
thread_local int Duct::mut_stem_counter = 0;
thread_local int Duct::mut_bipotent_counter = 0;
thread_local int Duct::mut_proglumepi_counter = 0;
thread_local int Duct::mut_lumepi_counter = 0;

thread_local int Duct::thread_index = 0;
thread_local vector<int> Duct::index_array;
thread_local Coordinate  Duct::boundaries = null_coordinate;

// Constructor
Duct::Duct(int l, int r, bool h, int n) :
    length(l),
    radius(r),
    HGP(h),
    diameter(r*2),
    n_threads(n),
    local_initialized(n,false)
{
    duct_type          = new uint8_t**[length];
    duct_housekeeping  = new uint8_t**[length];
    duct_protooncogene = new uint8_t**[length];
    duct_supressor     = new uint8_t**[length];
    duct_apoptosis     = new uint8_t**[length];

    for(int z=0 ; z<length ; z++)
    {
        duct_type[z]          = new uint8_t*[diameter];
        duct_housekeeping[z]  = new uint8_t*[diameter];
        duct_protooncogene[z] = new uint8_t*[diameter];
        duct_supressor[z]     = new uint8_t*[diameter];
        duct_apoptosis[z]     = new uint8_t*[diameter];

        for(int y=0 ; y<diameter ; y++)
        {
            duct_type[z][y]          = new uint8_t[diameter];
            duct_housekeeping[z][y]  = new uint8_t[diameter];
            duct_protooncogene[z][y] = new uint8_t[diameter];
            duct_supressor[z][y]     = new uint8_t[diameter];
            duct_apoptosis[z][y]     = new uint8_t[diameter];

            for(int x=0 ; x<diameter ; x++)
            {
                duct_type[z][y][x] = 0;
                duct_housekeeping[z][y][x] = 0;
                duct_protooncogene[z][y][x] = 0;
                duct_supressor[z][y][x] = 0;
                duct_apoptosis[z][y][x] = 0;
            }
        }
    }

    //...

    if(n_threads > 1)
    {
        thread_barrier = new CyclicBarrier(n_threads + 1); 
        thread_locks   = vector<mutex>(n_threads-1);
    }
}

// The "Runnable"
void Duct::run(int begin, int end, int index)
{
    thread_index = index;
    boundaries = Coordinate(begin, end, 0);
    for(int z=begin ; z<=end ; z++)
    {
        index_array.push_back(z);
    }

    for (int i=0; i<total_generations; i++)
    {
        thread_barrier->await();
        next_generation();
        update_global_counters();
    }
}

void Duct::execute(int nGens)
{
    int step = length/n_threads;
    for(int i=0 ; i<n_threads ; i++)
    {
        int begin =     i*step;
        int end   = (i+1)*step-1;
        if ((i+1) == n_threads)
            end = length-1;
        // Passing pointer to ourselves to avoid having to make a whole bunch of variables static
        thread_array.push_back(thread(&Duct::run, this, begin, end, i));
    }
    for (int i=0; i<total_generations ; i++)
    {
        // ...
        thread_barrier->await();
    }    
    for(int t=0 ; t<n_threads ; t++)
    {
        // Program crashes here. Wrapping this in a if(joinable()) doesn't fix it
        thread_array[t].join();
    }
}

Duct::~Duct()
{
    delete thread_barrier;
    for(int z=0 ; z<length ; z++) {
        for(int y=0 ; y<diameter ; y++) {
            delete[] duct_type[z][y];
            delete[] duct_apoptosis[z][y];
            delete[] duct_supressor[z][y];
            delete[] duct_housekeeping[z][y];
            delete[] duct_protooncogene[z][y];
        }
        delete[] duct_type[z];
        delete[] duct_apoptosis[z];
        delete[] duct_supressor[z];
        delete[] duct_housekeeping[z];
        delete[] duct_protooncogene[z];
    }
    delete[] duct_type;
    delete[] duct_apoptosis;
    delete[] duct_supressor;
    delete[] duct_housekeeping;
    delete[] duct_protooncogene;
}

int main() 
{
    int longitud = 50;
    int radio    = 10;
    int n_gens   = 50;
    int n_hilos  = 4;

    chrono::time_point<chrono::steady_clock> tic, toc;

    tic = chrono::steady_clock::now();
    Duct duct1(longitud, radio, true, n_hilos);
    duct1.execute(n_gens);
    toc = chrono::steady_clock::now();
    double elapsed = chrono::duration_cast<chrono::nanoseconds>(toc-tic).count();
    cout << elapsed * 1e-9 << endl;
    return 0;
}

0 个答案:

没有答案