【问题标题】:Multithreaded program goes in segmentation fault because of an argument由于参数,多线程程序进入分段错误
【发布时间】:2015-06-30 15:15:49
【问题描述】:

我遇到了一个多线程程序的奇怪问题,我将只报告部分代码。当我尝试运行它时,我收到一个分段错误错误。使用 gdb 和 valingrind 我发现问题出在我尝试取消引用 info 时,例如在 for(i=0; i<info->subm_n; i++) 中。 最奇怪的是,如果我在strncpy() 之后进行演员info=(c_args*)a,它只会在收集器的线程退出时进入分段错误。 我使用的是 64 位操作系统,并且我读到这有时会在 pthread_create() 中转换为 void* 时出现问题,我什至不知道是不是这样。 有人有什么想法吗? 附注带有大写字母的系统调用只是对我也测试失败的女巫中的功能的重新定义

typedef struct collector_arguments{
  int subm_n;
  int chronon;
   planet_t *p;
}c_args;


static void* collector(void* a) {
  int fd_skt,fd_sincro,tmp,i=0;
   c_args *info;
   struct sockaddr_un sa;
   info=(c_args*) a;

  strncpy(sa.sun_path,"visual.sck" ,MAXPATH);
  sa.sun_family=AF_UNIX;

  if((fd_sincro=open("SINCRO",O_RDWR))==-1) {
      perror("collector unable to open SINCRO fifo");fflush(stdout);
      pthread_exit(&errno);
   }
  for(i=0; i<info->subm_n; i++) {
    if (read(fd_sincro,&tmp,sizeof(int))==-1){
         perror ("collector Unable to read");fflush(stdout);
         pthread_exit(&errno);
    }
    fd_skt=Socket(AF_UNIX,SOCK_STREAM,0);
    while (connect(fd_skt,(struct sockaddr*)&sa, sizeof(sa)) == -1 ) {
        if ( errno == ENOENT )  sleep(1);
        else {
            perror ("client unable to connect to socket");fflush(stdout);
            pthread_exit (&errno);
        }
    }
    Write(fd_skt,&i,sizeof(int));
    Close(fd_skt);
  }
  Close(fd_sincro);
  pthread_exit((void*) 0);
}




static pthread_mutex_t fifo_mtx = PTHREAD_MUTEX_INITIALIZER;

static void* dispatcher(void* a) {
coordinate *c;
wator_t* w;
int i,j,fifo;
pthread_t tid_collector;

c_args *info=malloc (sizeof(c_args));
w=(wator_t*) a; 
c=(coordinate*) malloc(sizeof(coordinate));
c->numr=2;
c->numc=2;
while ( ((w->plan->nrow / c->numr) * (w->plan->ncol / c->numc))>NWORK_DEF && (w->plan->nrow > 2*c->numr) && (w->plan->ncol > 2*c->numc) ){
    if ( (w->plan->nrow / c->numr) >= (w->plan->ncol / c->numc) )       
        c->numr=c->numr*2;
    else 
        c->numc=c->numc*2;
    }


if ((w->plan->nrow % c->numr)==0) i=(w->plan->nrow / c->numr);
else i=(w->plan->nrow / c->numr)+1;
if ((w->plan->ncol % c->numc)==0) j=(w->plan->ncol / c->numc);
else j=(w->plan->ncol / c->numc)+1;
info->subm_n=i*j;
info->chronon=0;
info->p=w->plan;
while(1){
    reset_updated(w);
    (info->chronon)++;

    Pt_create( &tid_collector, NULL,&collector,(void*) info);

    for(i=0; i< w->plan->nrow; i+=c->numr)
        for(j=0; j< w->plan->ncol; j+=c->numc){     
            if((fifo=open("FIFO",O_WRONLY))==-1){
                perror("dispatcher unable to open FIFO");fflush(stdout);
                pthread_exit(&errno);
                }
            c->rowi=i;
            c->coli=j;
            Write(fifo, c, sizeof(*c));
            Close(fifo);
            }
    i=( (i/c->numr) * (j/c->numc) );
    Pt_join( tid_collector,NULL);
    }
return NULL;
}

【问题讨论】:

  • 我首先注意到的一件事是您正在使用 pthread_t tid_collector;然后将其传递给每个 pthread_create。每次执行此操作时,都会破坏该线程标识符,并且不能再 pthread_join 该特定线程,只能加入最新创建的线程。您应该改为创建一个 pthread_t 数组,并在每次迭代时递增传递给 pthread_create 的索引。
  • 我在复制代码时出错了,在join while结束后,这样每次while块执行时只会创建一个collector,而不是创建多个collector同时。
  • 对于所示代码,左/右大括号的数量不匹配。请修复这个问题,以及这个“奇怪”且至少不一致的缩进。
  • 似乎某些操作损坏了堆栈。尝试观察,例如,在 gdb 下执行期间的 info 变量。
  • @user2676680,他在循环的每次迭代结束时加入创建的线程,因此他一次不需要记住多个线程标识符。

标签: c multithreading pthread-join


【解决方案1】:

strncpy(sa.sun_path,"visual.sck" ,MAXPATH);

MAXPATH 是什么?

不要忘记strncpy() 将零填充到MAXPATH chars。

在 linux 上,sun_path 被定义为 108 个字符长,所以如果 MAXPATH 大于该值(或您系统上使用的任何值),那么您处于未定义行为的领域 - 出现此类错误 -通常意味着内存损坏最终导致段错误:

#define UNIX_PATH_MAX   108

struct sockaddr_un {
    __kernel_sa_family_t sun_family; /* AF_UNIX */
    char sun_path[UNIX_PATH_MAX];   /* pathname */
};

【讨论】:

  • 问题有效,但都不是有效的答案。此外,strncpy() 不会填零。
  • '如果src的长度小于n,strncpy()会向dest写入额外的空字节,保证总共写入n个字节。'
  • 有一个 #define MAXPATH 200 我没有显示,但我不明白这可能是什么问题
  • 我的错,strncpy() 确实垫。但这仍然不是一个答案,尽管它可能是一个领先的答案。
  • 因此,实际答案将涉及添加类似“您正在覆盖 sockaddr_un 结构的边界,从而产生未定义的行为。这可以很好地解释您的段错误,但它几乎可以肯定地解释了为什么行为会因您执行 strncpy() 的点而异。”
【解决方案2】:

不是答案,而是这段代码的用途:

for(i=0; i<info->subm_n; i++) {
    if (read(fd_sincro,&tmp,sizeof(int))==-1){
         perror ("collector Unable to read");fflush(stdout);
         pthread_exit(&errno);
    }

你为什么不fseek 然后只读取一个字节?或者读取至少 4k(甚至更好的块大小字节,然后根据需要进行访问...

【讨论】:

  • 和 fifo 的打开/关闭你会被移到循环之外,性能方面......
【解决方案3】:

如果您认为这是内存泄漏、堆栈损坏等问题。为什么不试试 valgrind 之类的内存调试器(请参阅 http://http://valgrind.org/)。

它至少会告诉您是否遇到内存问题、写入超出数组末尾等问题。

【讨论】:

  • 如果您认为这是一个答案,何不尝试阅读帮助中心关于编写答案的部分(请参阅stackoverflow.com/help/how-to-answer)。它会告诉你为什么你被否决。
  • 另外,OP 已经提到他使用了 Valgrind。他就是这样定位问题的。
  • D'oh,完全错过了原始评论,你得到的是阅读障碍!
猜你喜欢
  • 2015-06-09
  • 1970-01-01
  • 2015-11-08
  • 2011-12-29
  • 2018-11-02
  • 2016-02-09
  • 2018-04-25
相关资源
最近更新 更多