下面是一个示例,但这里是整个代码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;
}