2011-02-17 47 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確切的原型,但通常它也是一個壞主意,用固定鍵對於這種類型的功能。應該有一些函數返回你在你的應用程序中使用的一些鍵。