线程不在 Linux 上终止,但在 Mac 上终止

Threads not terminating on Linux but on Mac

本文关键字:终止 但在 Mac Linux 线程      更新时间:2023-10-16

我目前正在研究一种遗传算法,其中使用不同的独立线程计算新种群。我的程序在 OSX 上运行良好,但某些线程在 Linux 机器上不会终止。

我有以下方法,每个线程都会执行该方法,直到我生成了足够的个人。我正在使用一个互斥锁,它是人口类的一部分(因为这种方法就是这样)。因此,互斥对象不是静态的。该方法传递一组parents它可以在第一个parents_max的父母身上选择一个来生成一个新的孩子。子项是由另一个父对象突变或重组产生的。在select_randomlybool_with_prob中,我使用了来自<random>的几个分布(所有局部变量)来选择一个随机父级或为我提供一个随机布尔值。

我在互联网上搜索了线程不会终止的原因,并在使用std::random_devicestd::mt19937对象的方法周围添加了服务器(可能是不必要的)锁。

void generate_childs(std::set<individual> &parents, double mutation_rate, size_t parents_max)
{
size_t individuals_size;
{
boost::lock_guard<boost::mutex> lock(mutex);
individuals_size = individuals.size();
}
auto selectable_parents_end = parents.begin();
std::advance(selectable_parents_end, parents_max);
while(individuals_size < size)
{
mutex.lock();
individual male = *utilities::container::select_randomly(parents.begin(), selectable_parents_end);
bool generate_child = utilities::container::bool_with_prob(0.3);
mutex.unlock();
boost::optional<individual> ind;
if(generate_child)
{
mutex.lock();
individual female = *utilities::container::select_randomly(parents.begin(), parents.end());
mutex.unlock();
ind = mutation::combined_mutated_child(male, female, mutation_rate);
} else
{
ind = mutation::mutated_child(male, 0.9);
}
if(ind && ind->is_valid())
{
boost::lock_guard<boost::mutex> lock(mutex);
if (individuals.size() < size) {
individuals.insert(*ind);
}
}
{
boost::lock_guard<boost::mutex> lock(mutex);
individuals_size = individuals.size();
}
}
}

我像这样启动线程:

unsigned int number_of_threads = std::thread::hardware_concurrency();
auto parents = individuals;
std::vector<boost::thread> threads;
for(size_t i = 0; i<number_of_threads; i++)
{
threads.emplace_back(&population::generate_childs,
this,
std::ref(parents),
mutation_rate,
parents_max);
}
for(auto &t: threads)
{
t.join();
std::cout << "Thread finished" << individuals.size()  << std::endl;
}

在使用 Clang 编译的本地 (OSX) 机器上执行我的程序时,它按预期执行。在我的 Linux 机器上,它没有完成。我什至尝试设置number_of_threads=1,但没有帮助。当程序在我的 Linux 机器上没有终止时,我无法通过Ctrl+C退出它。我可能遇到竞争条件或死锁的任何想法?

编辑

按照建议,我打印了一个注释,其中包含每个线程的线程 ID。显然,我在更新大小时使用锁是不合适的。因此,我修改了最后一个锁,如下所示:

std::cout << i << " updating size" << std::endl;
{
std::cout << i << " updating size about to lock" << std::endl;
boost::lock_guard<boost::mutex> lock(configuration::mutex);
std::cout << i << " updating size about to locked" << std::endl;
individuals_size = individuals.size();
if(individuals_size >= size)
{
std::cout << i << " returning" << std::endl;
return;
}
}

我的程序的输出是这样的(跳过了线程工作正常的部分):

0 started
2 started
3 started
3 entered while
0 entered while
1 started
2 entered while
1 entered while
3 got male 1
0 got male 0
3 got female
2 got male 1
1 got male 1
2 got female
1 got female
0 got mutated
0 before is valid
0 inserting
0 inserted
0 updating size
0 updating size about to lock
0 updating size about to locked
0 returning
Thread finished10
2 got combined
2 before is valid
2 inserting
2 inserted
2 updating size
2 updating size about to lock
2 updating size about to locked
2 returning

在此之后,我没有得到任何额外的输出。对我来说,锁罩似乎不会释放互斥锁。是我加入线程的顺序吗?因为我尝试在线程 1 之前加入线程 2,即使它还没有完成?

我不喜欢你的代码中的一件事是你滥用了锁。例如,当您检索容器的大小时,您无法确定刚刚检索的大小在解锁互斥锁后是正确的。因此,正确的模式可能是锁定您检索大小的代码块并使用容器,假设此大小是正确的 - 并在不再需要此容器时解锁它。

因此,您应该重新设计代码,因为许多地方可能存在竞争条件。您的问题的一个可能答案,请查看下面的代码:

mutex.lock();
individual male = *utilities::container::select_randomly(parents.begin(), selectable_parents_end);
bool generate_child = utilities::container::bool_with_prob(0.3);
mutex.unlock();

什么是select_randomly中抛出的异常?您永远不会解锁互斥锁,这是一个死锁条件。为什么它会引发异常?例如,由于争用条件,值selectable_parents_end已过时。

相关文章: