【问题标题】:std::async is causing segmentation fault (or slow)std::async 导致分段错误(或慢)
【发布时间】:2021-06-14 02:24:06
【问题描述】:

我编写了简单的类来求解线性方程组,以并行化我使用 std::async 的矩阵行减法。在 10x10 矩阵大小之后,程序由于分段错误而崩溃。 我的第一个实现是用 std::async(std::launch::async, vecSub, std::ref(mat[c]), std::ref(temp)) 替换 vecSub((mat[c]), (temp)); 但后来发现如果我们不将它分配给任何变量析构函数被调用并且 .get() 被调用,并停止主线程(这就是它的原因减慢了),所以我将其更改为以下实现,现在我遇到了段错误
这是单线程:

class solver
{
    Mat mat;

public:
    //give eqn in the form ax1+ax2+ax3..axN = k (coeffiants only)
    Vec solve(Mat &in)
    {

        mat = in;

        ge(mat);
        return (bs(mat));
    }
    Vec solve(Mat &&in)
    {
        mat = std::move(in);
        ge(mat);
        return (bs(mat));
    }

private:
    void ge(Mat &mat)
    {

        using li = long int;

        for (li p = 0; p < mat[0].size() - 1; p++)
        {
            for (li c = p + 1; c < mat.size(); c++)
            {
                auto x = mat[c][p] / mat[p][p];
                auto temp = mat[p];
                vecMul(x, temp);
                vecSub((mat[c]), (temp));
    
            }
        }
    }
    Vec bs(Mat &mat)
    {
        using li = long int;
        Vec x(mat.size());
        for (li i = mat.size() - 1; i >= 0; i--)
        {
            double s = 0;
            for (li j = i; j < mat[0].size() - 1; j++)
            {
                s += mat[i][j] * x[j];
                x[i] = ((mat[i][mat[0].size() - 1] - s) / (mat[i][i]));
            }
        }
        return x;
    }
    static void vecMul(double a, Vec &b)
    {
        using li = size_t;
        for (li i = 0; i < b.size(); i++)
            b[i] *= a;
    }
    //static
    static void vecAdd(Vec &a, Vec &b)
    {
        using li = size_t;
        assert(a.size() == b.size());
        for (li i = 0; i < a.size(); i++)
            a[i] = a[i] + b[i];
    }
    static void vecSub(Vec &a, Vec &b)
    {
        using li = size_t;
        assert(a.size() == b.size());
        for (li i = 0; i < a.size(); i++)
            a[i] = a[i] - b[i];
    }
};

多线程

class solver
{
    Mat mat;

public:
    //give eqn in the form ax1+ax2+ax3..axN = k (coeffiants only)
    Vec solve(Mat &in)
    {

        mat = in;

        ge(mat);
        return (bs(mat));
    }
    Vec solve(Mat &&in)
    {
        mat = std::move(in);
        ge(mat);
        return (bs(mat));
    }

private:
    void ge(Mat &mat)
    {

        using li = long int;

        for (li p = 0; p < mat[0].size() - 1; p++)
        {
            std::vector<std::future<void>> ts;

            for (li c = p + 1; c < mat.size(); c++)
            {
                auto x = mat[c][p] / mat[p][p];
                auto temp = mat[p];
                vecMul(x, temp);
                ts.push_back(std::async(std::launch::async, vecSub, std::ref(mat[c]), std::ref(temp)));
            }
            for (auto &t : ts)
            {

                t.get();
            }
        }
    }
    Vec bs(Mat &mat)
    {
        using li = long int;
        Vec x(mat.size());
        for (li i = mat.size() - 1; i >= 0; i--)
        {
            double s = 0;
            for (li j = i; j < mat[0].size() - 1; j++)
            {
                s += mat[i][j] * x[j];
                x[i] = ((mat[i][mat[0].size() - 1] - s) / (mat[i][i]));
            }
        }
        return x;
    }
    static void vecMul(double a, Vec &b)
    {
        using li = size_t;
        for (li i = 0; i < b.size(); i++)
            b[i] *= a;
    }
    //static
    static void vecAdd(Vec &a, Vec &b)
    {
        using li = size_t;
        assert(a.size() == b.size());
        for (li i = 0; i < a.size(); i++)
            a[i] = a[i] + b[i];
    }
    static void vecSub(Vec &a, Vec &b)
    {
        using li = size_t;
        // assert(a.size() == b.size());
        for (li i = 0; i < a.size(); i++)
            a[i] = a[i] - b[i];
    }
};

分割发生在

static void vecSub(Vec &a, Vec &b)
    {
        using li = size_t;
        assert(a.size() == b.size());
        for (li i = 0; i < a.size(); i++)
            a[i] = a[i] - b[i];
    }

【问题讨论】:

    标签: c++ linux g++ stdasync


    【解决方案1】:

    无论Mat 是什么类型,我都非常确定:

    auto temp = mat[p];
    

    不创建引用而是创建副本。就是这个意思

    ts.push_back(std::async(std::launch::async, vecSub, std::ref(mat[c]), std::ref(temp)));`
    

    实际上引用了一个临时值temp,该值将在循环结束时被销毁。这是未定义的行为。
    这可能会解决问题:

    auto& temp = mat[p];
    

    【讨论】:

    • 这就是为什么当它按顺序运行时没有出现问题,但就像你告诉它异步运行时它会超出范围
    • 嘿,你的解决方案不起作用,因为 vecMul() 修改了原始矩阵,这会给出垃圾值,还有其他想法吗??
    • 还会崩溃吗?
    • 它没有崩溃,我不能使用参考,因为它会改变原始矩阵。它没有错误,但异步版本要慢得多,here is the updated problem
    • 如果它不再崩溃(这是原始问题),则将其标记为 [已解决],因为您已经为新问题发布了新帖子。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 2013-09-16
    相关资源
    最近更新 更多