在C程序中获取分段错误

时间:2012-12-05 10:07:56

标签: c arrays pthreads segmentation-fault

我在下面的代码中第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 ?? ()

但是,我无法纠正错误。

非常感谢Anyhelp。

2 个答案:

答案 0 :(得分:1)

请在start_thread中显示主叫代码。

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

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

答案 1 :(得分:0)

我不知道你是否更改了_my_struct中数组的名称以隐藏它们的目的(公司机密信息,也许?),但是如果这样的话实际上你将你的阵列命名为什么,我只是建议你给他们命名一些对你有用的东西,当有人在4年后阅读你的代码时,他们会有一些希望遵循你的初始化循环&amp;了解发生了什么。您的循环变量iG也是如此。

我的下一个评论/问题是,你为什么要开始一个线程来初始化主线程堆栈上的这个结构?一旦初始化了哪个线程将使用该结构?或者你打算使用其他线程来使用它?你有没有任何机制(互斥?信号量?)来确保其他线程不会开始使用数据,直到你的初始化线程初始化它为止?哪种问题引起了疑问,为什么你要打扰一个单独的线程来初始化它呢?您可以通过直接从main()调用populate_data()来初始化它,甚至不必担心同步,因为在完成初始化之前,您甚至不会启动任何其他线程。如果您正在多核计算机上运行,​​那么当main()继续运行时,您可以通过触发该单独的线程进行初始化来获得一些小的好处。做其他的东西,但从你的结构的大小(不是很小,但也不是很大)似乎这种好处将是非常微小的。如果你在一个核心上运行,你根本就不会获得并发利益;由于上下文切换开销,你只是浪费时间从另一个线程开始执行它;在一个单一的环境中,你最好直接从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()调用会使错误消失并不一定意味着你的循环逻辑是正确的,它只是意味着现在这些位置被认为是&#34;初始化&#34;由valgrind。如果在初始化循环开始时在这些位置具有全零是您的逻辑需要的,那么应该修复它。但是你需要自己验证这是否是正确的解决方案。

BTW ......有人建议使用calloc()来获得一个归零分配(而不是使用脏堆栈空间)......这也可以工作,但是如果你想让populate_data()变得万无一失,那你就是&#39 ; ll将内存归零而不是调用者,因为(假设您喜欢初始化逻辑),populate_data()依赖于它被清零,main()不应该这样做关心它是否是。无论如何都不是一件大事。