在C程序中获取分段错误



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

但是,我无法更正错误。

非常感谢您的帮助。

请在start_thread中显示调用代码。

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

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

我不知道你是否更改了_my_struct中数组的名称以隐藏它们的用途(也许是公司机密信息,他们将有一些希望遵循您的初始化循环&了解发生了什么。循环变量iG也是如此。

我的下一个评论/问题是,为什么要启动一个线程来初始化主线程堆栈上的这个结构?初始化后,哪个线程将使用此结构?或者你打算制作其他线程来使用它?您是否有任何机制(互斥?信号量?)来确保其他线程在初始化线程完成初始化之前不会开始使用数据?这就引出了一个问题,为什么你一开始就要启动一个单独的线程来初始化它;您可以直接从main()调用populateddata()来初始化它,甚至不必担心同步,因为在初始化完成之前,您甚至不会启动任何其他线程。如果你在多核机器上运行,当main()继续运行时,你可能会从启动单独的线程来进行初始化中获得一些小好处;做其他事情,但从你的结构的大小来看(不是很小,但也不是很大),这似乎是非常微小的好处。如果您在单个核心上运行,则根本不会获得并发优势;由于上下文切换开销,您只会浪费时间启动另一个线程来执行此操作;在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()不必关心它是否为零。不管怎样都不是什么大事。

相关内容

  • 没有找到相关文章

最新更新