1

我在下面的代码中的第 8 行遇到分段错误。

typedef struct _my_struct {
     int pArr[21];      
     int arr1[8191];
     int arr2[8191];
     int m;
     int cLen;
     int gArr[53];  
     int dArr[8191]; 
     int data[4096];
     int rArr[53]; 
     int eArr[1024];

};

void *populate_data(void *arg) {
1   register int mask =1, iG;
2   struct _my_struct *var ;
3   var = arg;                         // arg is passed as initialized struct variable while creating thread
4   var->m = 13;
5   var->arr2[var->m] = 0;
6   for (iG = 0; iG < var->m; iG++) {
7       var->arr2[iG] = mask;
8       var->arr1[var->arr2[iG]] = iG;
9       if (var->pArr[iG] != 0)         // pArr[]= 1011000000001
10          var->arr2[var->m] ^= mask;
11      mask <<= 1;
12  }
13  var->arr1[var->arr2[var->m]] = var->m;
14  mask >>= 1;
15  for (iG = var->m+ 1; iG < var->cLen; iG++) {
16      if (var->arr2[iG - 1] >= mask)
17          var->arr2[iG] = var->arr2[var->m] ^ ((var->arr2[iG- 1] ^ mask) << 1);
18      else
19          var->arr2[iG] = var->arr2[iG- 1] << 1;
20      var->arr1[var->arr2[iG]] = iG;
21  }
22  var->arr1[0] = -1;
   }

这是线程函数:

void main() {
        unsigned int tid;

        struct _my_struct  *instance = NULL;
        instance = (struct _my_struct  *)malloc(sizeof(_my_struct ));

        start_thread(&tid , 119312, populate_data, instance );          
}

int 
start_thread(unsigned int *tid, int stack_size, void * (*my_function)(void *), void *arg)
{
        pthread_t ptid = -1;
        pthread_attr_t pattrib;

        pthread_attr_init(&pattrib);

        if(stack_size > 0)
        {
            pthread_attr_setstacksize(&pattrib, stack_size);
        }
        else
        {
            pthread_attr_destroy(&pattrib);
            return -1;
        }

        pthread_create(&ptid, &pattrib, my_function, arg);      
        pthread_attr_destroy(&pattrib);

        return 0;
}

一旦我通过 gdb 调试它,就会出现这个错误,

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffdfec80700 (LWP 22985)]
0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:19
19                     var->arr1[var->arr2[iG]] = iG;

它的回溯是:

#0  0x0000000000401034 in populate_data (arg=0x7fffffffe5d8) at Queue.c:159
#1  0x00007ffff7bc6971 in start_thread () from /lib/libpthread.so.0
#2  0x00007ffff792292d in clone () from /lib/libc.so.6
#3  0x0000000000000000 in ?? ()

但是,我无法纠正错误。

非常感谢任何帮助。

4

2 回答 2

1

请在 中显示调用代码start_thread

它似乎可能是堆栈和/或内存分配错误,结构非常大(假设 32 位为 8 MB int)并且很可能会溢出一些堆栈限制。

更有可能的是它超出了范围,这就是必须显示调用步骤的原因。

于 2012-12-05T10:11:07.367 回答
0

我不知道您是否更改了 _my_struct 中数组的名称以隐藏它们的用途(可能是公司机密信息?),但如果这实际上是您命名数组的名称,我我只是建议你给它们命名一些对你有意义的东西,当有人必须在 4 年后阅读你的代码时,他们会有一些希望遵循你的初始化循环并理解正在发生的事情。你的循环变量也是如此iG

我的下一个评论/问题是,你为什么要启动一个线程来初始化主线程堆栈上的这个结构?一旦初始化,哪个线程将使用这个结构?或者你打算制作其他线程来使用它?您是否有任何机制(互斥量?信号量?)来确保其他线程在您的初始化线程完成初始化之前不会开始使用数据?哪一种引出了问题,你为什么要费心启动一个单独的线程来初始化它?您可以通过直接从 main() 调用 populate_data() 来初始化它,甚至不必担心同步,因为在完成初始化之前您甚至不会启动任何其他线程。如果你在多核机器上运行,您可能会从启动该单独线程以在 main() 继续进行初始化并执行其他操作时获得一些小好处,但是从结构的大小(不是很小,但也不是很大)看来,这种好处将是非常微小。而且,如果您在单核上运行,则根本不会获得并发优势;由于上下文切换开销,您只会浪费时间启动另一个线程来执行此操作;在 unicore 环境中,最好直接从 main() 调用 populate_data()。根本不会获得并发收益;由于上下文切换开销,您只会浪费时间启动另一个线程来执行此操作;在 unicore 环境中,最好直接从 main() 调用 populate_data()。根本不会获得并发收益;由于上下文切换开销,您只会浪费时间启动另一个线程来执行此操作;在 unicore 环境中,最好直接从 main() 调用 populate_data()。

下一条评论是,您的 _my_struct 并不大,因此它不会自行破坏您的堆栈。但它也不小。如果您的应用程序总是只需要这个结构的一个副本,也许您应该将其设为全局变量或文件范围变量,这样它就不会占用堆栈空间。

最后,到你的实际错误............

我没有费心去尝试破译你神秘的循环代码,但 valgrind 告诉我你有一些条件取决于未初始化的位置:

~/test/so$ valgrind a.out
==27663== Memcheck, a memory error detector
==27663== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==27663== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==27663== Command: a.out
==27663==
==27663== Thread 2:
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x8048577: populate_data (so2.c:34)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)
==27663==
==27663== Conditional jump or move depends on uninitialised value(s)
==27663==    at 0x804868A: populate_data (so2.c:40)
==27663==    by 0x593851: start_thread (in /lib/libpthread-2.5.so)
==27663==    by 0x4BDA8D: clone (in /lib/libc-2.5.so)

我的 so2.c 第 34 行对应于您上面发布的代码中的第 9 行。我的 so2.c 第 40 行对应于您上面发布的代码中的第 15 行。

如果我在 populate_data() 的顶部添加以下内容,这些 valgrind 错误就会消失:

memset(arg,0,sizeof(_my_struct_t));

(我修改了你的结构定义如下:)

typedef struct _my_struct { int pArr[21]; ......... } _my_struct_t;

现在仅仅因为添加 memset() 调用使错误消失并不一定意味着你的循环逻辑是正确的,它只是意味着现在这些位置被 valgrind 视为“初始化”。如果在初始化循环开始时在这些位置有全零是您的逻辑所需要的,那么应该可以解决它。但是您需要自己验证这确实是正确的解决方案。

顺便说一句...有人建议使用 calloc() 来获得归零分配(而不是使用脏堆栈空间)...这也可以,但是如果您希望 populate_data() 是万无一失的,那么您会将内存归零在其中而不是在调用者中,因为(假设您喜欢初始化逻辑), populate_data() 取决于它是否被清零, main() 不必关心它是否存在。无论哪种方式都不是什么大问题。

于 2012-12-05T15:35:09.353 回答