2011-02-17 39 views
1

我对C非常没有经验,并且遇到了一个我无法理解的原因的“总线错误”。我从来没有听说过的gdb的,但碰到它在这个论坛上,并用它在我的问题程序试图,得到了以下的输出:在Unix机器上的C程序中的总线错误

%GDB GNU过程Proc1 GDB 5.0

...

这是GDB配置 为 “Sun SPARC的-solaris2.8” ......

(没有发现 调试符号)...

(GDB)运行

启动程序:(没有发现 调试符号) /家庭/ 0 /弗尔切克/ CSE660/Lab3的/

过程Proc1

(没有发现 调试符号)...

......(没有发现 调试符号)

...

计划 接收信号SIGSEGV,分割 故障。在主要()0x10a64

我不知道这是什么意思,是说我的代码中有第10行的错误?如果是这样,我的代码中的第10行仅仅是“int main()”,所以我不知道那里的问题......当我尝试运行该程序时,它所说的是“总线错误”,所以我不确定在哪里从这里出发。我甚至试图在main之后放一个printf,它不打印字符串,只给了我一个总线错误。

下面是我的代码:

// Compilation Command: gcc -o Proc1 Proc1.c ssem.o sshm.o 

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include "ssem.h" 
#include "sshm.h" 

// Code of Proc1 
int main() 
{int i, internal_reg; 
int key1 = 111111, key2 = 222222, key3 = 333333, key4 = 444444; 
/* here create and initialize all semaphores */ 
int sem1 = sem_create(key1, 1); 
if (sem1 < 0) { 
    perror("sem failed"); 
} 
int sem2 = sem_create(key2, 1); 
if (sem2 < 0) { 
    perror("sem failed"); 
} 
int sem3 = sem_create(key3, 1); 
if (sem3 < 0) { 
    perror("sem failed"); 
} 
int sem4 = sem_create(key4, 1); 
if (sem4 < 0) { 
    perror("sem failed"); 
} 
/* here created: shared memory array Account of size 3 */ 
int *Account; 
int shmid = shm_get(123456, (void**) &Account, 3*sizeof(int)); 
if (shmid < 0) { 
    perror("shm failed"); 
} 
Account[0]=10000; 
Account[1]=10000; 
Account[2]=10000; 
/* synchronize with Proc2, Proc3 and Proc4 (4 process 4 way synchronization)*/ 

for (i = 0; i < 1000; i++) 
    { 
    sem_signal(sem1); 
    sem_signal(sem1); 
    sem_signal(sem1); 

internal_reg = Account[0]; 
    internal_reg = internal_reg - 200; 
    Account[0] = internal_reg; 

    /* same thing, except we're adding $100 to Account1 now... */ 
    internal_reg = Account[1]; 
    internal_reg = internal_reg + 200; 
    Account[1] = internal_reg; 

    if (i % 100 == 0 && i != 0) { 
     printf("Account 0: $%i\n", Account[0]); 
     printf("Account 1: $%i\n", Account[1]); 
    } 

    if (i == 300 || i == 600) { 
     sleep(1); 
    } 

    sem_wait(sem2); 
    sem_wait(sem3); 
    sem_wait(sem4); 
    } 
/*  Here add a code that prints contents of each account 
and their sum after 100th, 200th, 300th, ...., and 1000th iterations*/ 

} 

/*in the code above include some wait and signal operations on semaphores. Do no 
t over-synchronize. */ 

这里是SSEM和sshm文档:

/* 
* ssem.c 
* 
* Version 1.0.0 
* Date : 10 Jan 2002 
* 
*/ 


#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <sys/types.h> 

#include "ssem.h" 

#define PERMS 0600 

static struct sembuf op_lock[1] = { 
     0, -1, 0 
}; 

static struct sembuf op_unlock[1] = { 
     0, 1, IPC_NOWAIT 

}; 



int sem_create(int key,int initval) 
{ 
     int semid,i; 
     semid = semget((key_t)key, 1, IPC_CREAT | PERMS); 

     for(i=0;i<initval;i++) 
       semop(semid,&op_unlock[0],1); 


     return semid; 

} 

int sem_open(int key) 
{ 
     int semid; 
     semid = semget(key,0,0); 
     return semid; 
} 


int sem_wait(int semid) 
{ 
     return semop(semid,&op_lock[0],1); 
} 


int sem_signal(int semid) 
{ 
     return semop(semid,&op_unlock[0],1); 
} 


int sem_rm(int semid) 
{ 
     return semctl(semid, 0, IPC_RMID, 0); 
} 



/* 
* sshm.c 
* 
* Routines for Simpler shared memory operations 
* Version : 1.0.0. 
* Date : 10 Jan 2002 
* 
*/ 

#include <sys/shm.h> 
#include <sys/ipc.h> 
#include <sys/types.h> 

#include "sshm.h" 

#define PERMS 0600 

int shm_get(int key, void **start_ptr, int size) 
{ 
     int shmid; 
     shmid = shmget((key_t) key, size, PERMS | IPC_CREAT); 
     (*start_ptr) = (void *) shmat(shmid, (char *) 0, 0); 
     return shmid; 

} 


int shm_rm(int shmid) 
{ 
     return shmctl(shmid, IPC_RMID, (struct shmid_ds *) 0); 

} 

与-ggdb标志编译Proc1.c和运行gdb的我得到了以下后:

程序接收到的信号SIGSEGV, 分段错误。 0x10a64在main() 在Proc1.c:36

36科目[0] = 10000

为什么会这样导致段错误?

改变帐户的声明

int *Account = 0; 

和添加

printf("Account == %p\n", Account); 

帐户之前后[0] = 10000;

我得到运行时过程Proc1如下:

Account == ffffffff 
Bus error 
+0

参见http://stackoverflow.com/questions/212466/what-is-a-bus-error – Keith 2011-02-17 23:28:41

+1

用`-Wall`标志构建并查看编译器是否发出任何有用的警告。 – bta 2011-02-17 23:31:17

回答

1

为了得到GDB更多有意义的结果,你应该用-ggdb选项编译程序。这将包括调试信息(如行号)到您的程序中。

您目前看到的是程序计数器的内存地址(0x10a64)。除非您可以将您在其中找到的汇编指令与您的C程序的一部分相关联,否则这不会对您有所帮助。

看起来您正在正确使用shm_get。我认为图书馆设计人员在命名该功能时犯了一个可怕的错误,与shmget类似。

就像我想的那样。 Account指针结束于一个无效值(又名0xffffffff(又名(void *)(-1)))。值(void *)(-1)通常表示某种错误,并在shmat的联机帮助页中明确提到。这表明库中的shmat调用失败。这里是你如何判断它是否失败:

if (Account == (void *)(-1)) { 
    perror("shmat failed"); 
} 
Account[0] = 10000; 
// ... 

现在,它为什么失败是一个有趣的谜。显然shmget调用成功。

就我个人而言,我认为System V IPC在这一点基本上已被弃用,你应该避免使用它,如果你可以。

0

根据您的编译器和您的编译器选项,您可能会遇到别名问题,因为您正在投射您的Account指针的地址。这些古老的界面与现代反锯齿规则不同步,这意味着优化器假定Account的值不会改变。

此外,您应该获得shm_get尽可能接近预期类型的​​参数。试试或许像下面这样的东西。

void volatile* shmRet; 
int shmid = shm_get(123456, (void**) &shmRet, 3*sizeof(int)); 

int *Account = shmRet; 

我没有相同的架构,所以我不知道你shm_get确切的原型,但通常它也是一个坏主意,用固定键对于这种类型的功能。应该有一些函数返回你在你的应用程序中使用的一些键。