我遇到了一个多线程程序的奇怪问题,我将仅报告其中的部分代码。当我尝试运行它时,我收到分段错误错误。使用 gdb 和 valingrind 我发现问题是当我尝试取消引用
info
时,例如在 for(i=0; i<info->subm_n; i++)
中。
最奇怪的是,如果我在
info=(c_args*)a
之后进行强制转换strncpy()
,则仅当收集器线程退出时才会出现分段错误。
我使用的是 64 位操作系统,我读到这有时会在
void*
中转换为 pthread_create()
时出现问题,我什至不知道是否是这种情况。
有人有什么想法吗?
附注大写字母的系统调用只是对函数的重新定义,我也在其中测试失败
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;
}
strncpy(sa.sun_path,"visual.sck" ,MAXPATH);
什么是
MAXPATH
?
不要忘记
strncpy()
会将零填充到 MAXPATH
char
s。
在 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 */
};
不是答案,但是这段代码的用途是:
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(甚至更好的块大小字节,然后相应地访问...
如果您认为这是内存泄漏、损坏的堆栈问题等。为什么不尝试使用内存调试器,例如 valgrind(请参阅 http://http://valgrind.org/ )。
它至少会告诉您是否遇到内存问题、写入超出数组末尾等问题。