【问题标题】:Segmentation fault during thread.jointhread.join 期间的分段错误
【发布时间】:2015-10-19 17:36:04
【问题描述】:

我的代码有问题。当我将 argv[1] 增加到 4.294.967.295 (INT_MAX) 时,我遇到了分段错误,尽管我选择了“long long int”作为数据类型:

#define NUM_THREADS 5

// ...

int main (int argc, char **argv)
{
    // allocating memory and declaring threads
    std::thread thread[NUM_THREADS];    
    bool *sv_ptr = (bool *) calloc(atoll(argv[1]), sizeof(bool));

    short int t = 0;
    long long int i = 2;

    // initialize threads
    for (t = 0; t < NUM_THREADS; t++, i++)
        thread[t] = std::thread(remove_multiples, i, sv_ptr, atoll(argv[1]));

    t = 0; 
    while (i < atoll(argv[1]) || !threads_finished(thread))
    {
        if (sv_ptr[i] || thread[t].joinable())
        {
            // starting new tasks
            if (thread[t].joinable())
            {
                thread[t].join(); // <- segfault occurs here
                thread[t] = std::thread(remove_multiples, i, sv_ptr, atoll(argv[1]));
            }

            // printing results
            if (!sv_ptr[i-NUM_THREADS])
                std::cout << (i - NUM_THREADS) << std::endl;

            i++;
        }
        // increment thread iterator
        t = (t + 1) % NUM_THREADS;
    }
    // ...
}

void remove_multiples(long long int n, bool *sv_ptr, long long int max)
{
    for (int i = 2; i*n < max; i++)
    sv_ptr[i*n] = true;
}

bool threads_finished(std::thread *threads)
{
    for (int t = 0; t < NUM_THREADS; t++)
        if (!threads[t].joinable())
            return false;
    return true;
}

在加入可连接线程时发生分段错误。

感谢您的帮助!

编辑:我想在我的 16 GB 机器上测试堆分配,因此我编写了这个程序。我能够创建一个约 1.5 万亿布尔值的数组,并且我之前使用单线程程序做到了这一点。 分配时不会发生错误!我有足够的内存。它发生在线程管理中的某个地方

【问题讨论】:

  • 此代码段仅用于初始化所有 NUM_THREADS 个线程。我在 while 循环中遍历数组。
  • bool *sv_ptr = (bool *) calloc(atoll(argv[1]), sizeof(bool)); 我希望您使用 64 位并拥有大量 RAM,考虑到这将分配至少 4 GB,也许 16 GB。确定是这样吗?
  • 旁注:尽可能保持变量在本地(就声明和使用而言)(例如:for(short int t = 0; ...))并避免在不同的环境中循环使用变量上下文。
  • 我想测试堆分配,因此我想使用我的整个内存(16 GB)
  • @J.Doe,你试过调试你的程序吗?访问哪个地址会导致段错误?我在您的程序中看到至少一个潜在的段错误:calloc 失败并返回 NULL,其中一个线程抓住它并尝试访问 remove_multiples。繁荣。段错误。

标签: c++ multithreading c++11


【解决方案1】:

好的,我在调试器中运行了这段代码(在重新排列函数顺序并添加缺少的包含文件以便编译之后)。

对我来说,段错误发生在程序结束时。我强烈怀疑这个函数中的逻辑不正确:

bool threads_finished(std::thread *threads)
{
    for (int t = 0; t < NUM_THREADS; t++)
        if (!threads[t].joinable())
            return false;
    return true;
}

有两个原因:

  1. 如果任何线程不可加入,则返回 false(即不,未完成),并且

  2. 您无法检测线程是否已像这样完成。您需要让线程更新原子计数器/标志集或更好,一个受条件变量和互斥锁对保护的标志集,以便您可以正确 (a) 测试线程是否完整和 (b) 等待所有线程在main() 结束之前完成。

更新:

根据要求添加了参考。建议您将此网站加入书签。

已完成执行代码但尚未加入的线程仍被视为正在执行的活动线程,因此是可加入的。

http://en.cppreference.com/w/cpp/thread/thread/joinable

【讨论】:

  • 谢谢,这是第一个有用的答案。 1. 如果存在不可连接的线程,则并非所有线程都“完成”。否则他们是。我认为逻辑是正确的 2.我应该如何检查它,你有没有参考?
  • 首先感谢您的参考,我会收藏它。但看起来方法是正确的不是吗? “检查线程对象是否标识了一个活动的执行线程。”因此,当线程完成删除多个线程时,它是可连接的,因此正在寻找新任务。
  • 一个线程在运行和完成执行时都是joinable。只有在使用默认初始化对象或release()d 进行默认初始化、移出、移至时,它才为not joinable()
  • 哦,现在我明白你的意思了……我真的应该深入探讨这个话题。给定的程序是我第一次尝试多线程。
  • 注意 - 对于有经验的多线程开发人员来说,'join/joinable' 和 STD 一样受欢迎。 '分配时不会发生错误!我有足够的内存。它发生在线程管理的某个地方' - 是的,这正是您尝试微观管理线程时发生的情况。
猜你喜欢
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
  • 2019-04-06
  • 2015-12-23
  • 1970-01-01
相关资源
最近更新 更多