Ошибка шины в программе C на Unix-машине - PullRequest
1 голос
/ 18 февраля 2011

Я довольно неопытен с C и сталкиваюсь с "ошибкой шины", которую я не могу понять причину.Я никогда не слышал о GDB, но наткнулся на него на этом форуме и попытался использовать его в моей проблемной программе и получил следующий вывод:

% GDB Proc1 GNU GDB 5.0

...

Этот GDB был настроен как "sparc-sun-solaris2.8" ...

(символы отладки не найдены) ...

(gdb) run

Запуск программы: / home / 0 / vlcek / CSE660 / Lab3 / Proc1

(символы отладки не найдены) ...

(символы отладки не найдены) ...

(символы отладки не найдены) ...

Программный полученный сигнал SIGSEGV, Ошибка сегментации.0x10a64 в main ()

Понятия не имею, что это значит, это говорит о том, что в моем коде строка 10 содержит ошибку?Если это так, строка 10 в моем коде просто "int main ()", поэтому я не уверен, что проблема там ... Когда я пытаюсь запустить программу, все, что она говорит, "Ошибка шины", поэтому я не уверен, гдеперейти отсюда.Я даже попытался поместить printf сразу после main, и он не печатает строку, а только выдает ошибку Bus.

Ниже мой код:

// 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);

}

После компиляции Proc1.c с флагом -ggdb и запуска gdb я получил следующее:

Программа получила сигнал SIGSEGV, Ошибка сегментации.0x10a64 в main () в Proc1.c: 36

36 Account [0] = 10000

Почему это может вызвать ошибку сегментации?

После измененияобъявление учетной записи на

int *Account = 0;

и добавление

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

перед учетной записью [0] = 10000;

Я получаю следующее при запуске Proc1:

Account == ffffffff
Bus error

Ответы [ 2 ]

1 голос
/ 18 февраля 2011

Чтобы получить более разумные результаты от GDB, вы должны скомпилировать вашу программу с опцией -ggdb. Затем он включит информацию об отладке (например, номера строк) в вашу программу.

В данный момент вы видите адрес памяти (0x10a64) счетчика программ. Это не очень вам поможет, если вы не сможете соотнести найденные там инструкции по сборке с частью вашей программы на Си.

Похоже, вы используете 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 голосов
/ 18 февраля 2011

В зависимости от вашего компилятора и параметров компилятора вы можете столкнуться с проблемой псевдонимов, поскольку вы преобразуете адрес вашего указателя Account.Эти устаревшие интерфейсы не соответствуют современным правилам сглаживания, то есть оптимизатор предполагает, что значение Account не изменится.

Также вы должны получить аргумент для shm_get как можно ближе кожидаемый тип.Попробуйте, возможно, что-то вроде следующего.

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

int *Account = shmRet;

У меня нет той же архитектуры, поэтому я не знаю точного прототипа вашего shm_get, но обычно это также плохая идея использовать исправленныйклавиши для этого типа функций.Должна быть какая-то функция, которая возвращает вам ключ для использования в вашем приложении.

...