【问题标题】:Segfault after launching a new thread启动新线程后的段错误
【发布时间】:2011-10-10 04:39:29
【问题描述】:

我正在编写一个使用多个线程来处理传入订单的股票市场系统。

项目进展顺利,直到我又添加了一个线程。当我启动上述线程时,我的程序段错误。段错误是在上述线程中由无效的内存读取产生的。

此段错误在程序使用优化 -O2 及以上编译时生成。

使用 -g3 编译带有调试信息的程序并使用 valgrind 运行

valgrind ./marketSim

并获得有关段错误的以下输出

==2524== Thread 5:
==2524== Invalid read of size 4
==2524==    at 0x402914: limitWorker (limit.c:4)
==2524==    by 0x4E33D5F: start_thread (in /lib/libpthread-2.14.so)
==2524==  Address 0x1c is not stack'd, malloc'd or (recently) free'd
==2524== 
==2524== 
==2524== Process terminating with default action of signal 11 (SIGSEGV)
==2524==  Access not within mapped region at address 0x1C
==2524==    at 0x402914: limitWorker (limit.c:4)
==2524==    by 0x4E33D5F: start_thread (in /lib/libpthread-2.14.so)

线程是这样启动的

pthread_t limit_thread;
pthread_create(&limit_thread, NULL, limitWorker, q);

q 是变量,它也传递给我初始化的其他线程

limitWorker代码如下

void *limitWorker(void *arg){
    while(1){
        if ((!lsl->empty) && (!lbl->empty)) {
            if ((currentPriceX10 > lGetHead(lsl)->price1) && (currentPriceX10 < lGetHead(lbl)->price1)) {
                llPairDelete(lsl,lbl);
            }
        }
    }
    return NULL;
}

第4行:根据valgrind产生段错误的行是void *limitWorker(void *arg){

还有一些更多信息,这是使用 gcc 4.6.1 编译的,当使用 gcc 4.1.2 时,程序不会出现段错误,即使它经过优化,尽管它的性能要差得多。

当使用clang 编译程序时,优化时也不会出现段错误。

问题

我是不是搞错了??是gcc的错误吗??我应该采取什么行动?

如果你想看一下代码,github页面是https://github.com/spapageo/Stock-Market-Real-Time-System/

有问题的代码在文件marketSim.climit.c

编辑: Valgrind 指定无效读取发生在第 4 行。第 4 行是函数的“头”。我不知道编译器的内部结构,所以我天真的想法是这个论点是错误的。 BUT 在使用 gdb 时在 segfault 参数之后,因为程序已经优化,is optimized out 根据 gdb。所以我不认为那是罪魁祸首。

【问题讨论】:

    标签: c gcc pthreads segmentation-fault


    【解决方案1】:

    如果您正在为 64 位系统进行编译,则 0x1corder 结构中 price1 字段的偏移量。这意味着当故障发生时,lsl-&gt;HEADlbl-&gt;HEAD 中的任何一个(或两者)都是 NULL 指针。

    请注意,因为您的 limitWorker() 函数在 llPairDelete() 函数之外不包含线程同步,所以它是不正确的,编译器可能不会在每次执行循环时重新加载这些值。您应该使用互斥锁来保护链表即使在只读路径中

    此外,您的 lsllbl 变量是多重定义的。您应该在limit.h 中将它们声明为extern,并在limit.c 中定义它们而不使用extern

    【讨论】:

    • 我认为你成功了。是的,我正在 64 位系统中编译。我认为第一个 if 子句 if ((!lsl-&gt;empty) &amp;&amp; (!lbl-&gt;empty)) 可以保护我避免在第二个 if if ((currentPriceX10 &gt; lGetHead(lsl)-&gt;price1) &amp;&amp; (currentPriceX10 &lt; lGetHead(lbl)-&gt;price1)) 处超出 NULL 指针,但是编译器的优化和预加载却搞砸了我。另外我不明白如何声明 lsllbl 内部包括警卫又名 #ifndef LIMIT_H 与 extern 声明不同,因为它们都为我工作。
    • @Spyros:按照您的做法,每个包含limit.h.c 文件都定义了这些变量,这意味着您最终会得到多个定义。这是不允许的,具体发生的情况取决于您的链接器如何处理 - 只是不要这样做。
    • @Spyros: AFAIK,包含守卫可以避免在同一个文件中多次声明,但如果您想访问另一个文件中定义的变量,则需要 extern。
    • @puffadder 我猜,链接器为我处理了重复项。谢谢提醒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 2015-12-12
    相关资源
    最近更新 更多