1

我是 c++ 的新手,在玩 c++11 的线程时出现“分段错误(核心转储)”。我修改了一段我以前写的好代码并得到了错误。我修改的部分是

mutex m;
auto thread_f=[&](int i)
{
    for(int j=i; j<interval.size(); j+=Threads_Number)
    {
        vector<Permutation >::iterator it1=(interval.begin()+j);
        for(vector<Permutation >::iterator it2=it1; it2!=interval.end(); it2++)
        {
            if(!(*it1<*it2)) continue;
            IntervalToCheck x(*it1,*it2);
            m.lock();
            cout<<x;
            f<<x;
            m.unlock();
        }
    }
};

vector<thread> threads;
threads.clear();
for(int i=0; i<Threads_Number; i++)
    threads.push_back(thread(thread_f,i));
for(auto& th:threads)
    th.join();

其中变体“f”是 ofstream 的一个对象。奇怪的是,当我将“Threads_Number”设置为 1 时,程序运行良好,而当我将“Threads_Number”设置为 1 以外时,程序有时运行良好,有时运行不正常——就像我以前不初始化 int 时一样并使用它。

这是我的 g++ 版本:

aalen@CFC:multiThreads> g++ --version                                            13-02-25 14:24
g++ (GCC) 4.7.2
Copyright (C) 2012 Free Software Foundation, Inc.

我用:

g++ -c main.cpp --std=c++11

g++ *.o -o work -lcln -lginac -pthread 

编译我的代码。并感谢您的关注,对不起我糟糕的英语。

似乎是因为我在 IntervalToCheck 类中使用 GiNaC 并且它不是线程安全的(因为我在 Google 上搜索了 GiNac 和线程安全),因为我收到的消息是

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff5340700 (LWP 3125)]
0x00000000004097cf in GiNaC::ptr<GiNaC::basic>::operator= (this=0x7fffec000cd0,   other=...) at /usr/include/ginac/ptr.h:88
88              delete p;

正如 nm 所建议的,来自 gdb。也许 GiNaC 是问题所在。如果有人能提供一个处理表达的开放工具,那就太好了。谢谢阅读。

4

1 回答 1

0

如果您查看分段错误来自何处的源代码,您可以看到它来自 GiNaC 的引用计数指针实现。据我了解,问题是指针可能在另一个线程仍在使用它时被过早删除。这是因为计数器上的递增和递减操作在线程访问方面不是原子的。因此,您正在尝试访问已删除的内存,这是未定义的行为(因此可以进行段错误)。

实际上,过去似乎已经出现过这个问题,并且在他们的邮件列表中表达了担忧

据其维护者称,GiNaC 不是线程安全的。

因此,您根本不能按照维护者的意图从多个线程中使用 GiNaC。

从理论上讲,也许您可​​以ginac::ptr用类似的东西代替std::shared_ptr,这样可以保证在其引用计数机制方面没有竞争条件。因此,如果您可以将内部计数器类型替换为std::atomic<int>或类似的东西,或者您可以使用另一个具有原子引用计数的实现,那么该程序可能会工作。

至于您编写的实际代码,它似乎应该可以正常工作。std::scoped_lock尽管 print 语句可以按顺序执行和交错,但它们似乎正确地锁定在一个关键块中,尽管使用C++ 中更惯用的 RAII 增强型可能更好。

于 2017-02-07T12:35:16.257 回答