Проблема с общей памятью в C - PullRequest
0 голосов
/ 21 марта 2020

Я просто опубликовал свой предыдущий вопрос. Я просто сжал код настолько, насколько он работает, и функциональность такая же, как у основного проекта.

общая память. she_demo. c

#define DATA_LEN 10
char *key = "/shm1";

pthread_mutex_t mutex;
void initalize(void){
    pthread_mutex_init(&mutex, NULL);
}

void *reader(void* arg) {
    char pack[10];
    pthread_mutex_lock(&mutex);
    int shm_fd = shm_open(key, O_CREAT | O_RDONLY , S_IRUSR | S_IWUSR);
    if (shm_fd == -1) {
        printf("Could not open shared memory \n");
        return (void*)-1;
    }

    void *shmp_rd = mmap(NULL, DATA_LEN, PROT_READ, MAP_SHARED, shm_fd, 0);
    if(shmp_rd == MAP_FAILED){
        printf("Mapping failed\n");
        return (void*)-1;
    }

    memcpy(pack, shmp_rd, DATA_LEN);

    if (munmap(shmp_rd, DATA_LEN) == -1) {
        printf("Unmapping failed\n");
        return (void*) NULL;
    }
    shm_unlink(key);
    close(shm_fd);
    pthread_mutex_unlock(&mutex);

    return (void*)pack;
}

void *writer(void *arg) {
    char pack[10];
    strcpy(pack, (char*)arg);
    printf("%s\n", pack);
    pthread_mutex_lock(&mutex);
    int shm_fd = shm_open(key, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR);
    if (shm_fd == -1) {
        printf("Could not create shared memory\n");
        return (void*)-1;
    }

    if (ftruncate(shm_fd, DATA_LEN) == -1) {
        printf("Error on ftruncate to allocate \n");
        return (void*)-1;
    }

    void *shmp_wr =  mmap(NULL, DATA_LEN, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if(shmp_wr == MAP_FAILED){
        printf("Mapping failed\n");
        return (void*)-1;
    }
    memcpy(shmp_wr, pack, strlen(pack));

    if (munmap(shmp_wr, DATA_LEN) == -1) {
        printf("Unmapping failed\n");
        return (void*)-1;
    }
    pthread_mutex_unlock(&mutex);
    close(shm_fd);
    return (void*)1;
}

сервер. c

#define DATA_LEN 70
#define SOCKET_NAME "socket"

extern void *writer(void*);
extern void initalize(void);

int main(){
  char *item[6] ={"Bruno", "Ben", "Zack", "Jack"};
  pthread_t tid;
  int connection_socket, data_socket, ret; //crete socket
    struct sockaddr_un name;
    unlink(SOCKET_NAME);
    connection_socket = socket(AF_UNIX, SOCK_STREAM, 0);
    if(connection_socket == -1){
        perror("socket");
        return -1;
    }
    memset(&name, 0, sizeof(struct sockaddr_un));
    name.sun_family = AF_UNIX;
    strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) - 1);
    ret = bind(connection_socket, (const struct sockaddr *) &name, sizeof(struct sockaddr_un));
    if (ret == -1) {
        perror("bind");
        exit(1);
    }
    ret = listen(connection_socket, 20);
    if (ret == -1) {
        perror("listen");
        exit(1);
    }
    data_socket = accept(connection_socket, NULL, NULL);
    void* ret_vpr;
    int i = 0;
    char sync[5];
    strcpy(sync, "ADD");
    while(i < 4){
      printf("%d:\n", i);
      write(data_socket, sync, strlen(sync));

      pthread_create(&tid, NULL, writer, (void *)item[i]);
      pthread_join(tid, &ret_vpr);
      if((int)ret_vpr == 1){

      }
      i++;
    }
    close(data_socket);
      close(connection_socket);
    return 0;
}

клиент. c

#define DATA_LEN 70
#define SOCKET_NAME "socket"
extern void *reader(void*);

int main(void){
  pthread_t tid;
  char *item[4];
  void *ret_vpr;
    struct sockaddr_un addr;// create socket
    int data_socket = socket(AF_UNIX, SOCK_STREAM, 0);
    if (data_socket == -1) {
        perror("socket");
        exit(1);
    }
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, SOCKET_NAME, sizeof(addr.sun_path) - 1);
    if (connect(data_socket, (const struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) {
        fprintf(stderr, "The server is down.\n");
        exit(1);
    }
    printf("connected\n"); // create socket
    int rc = 1;
    char ch[6];
    while(rc){
      rc = read(data_socket, ch, sizeof(ch));
      if(rc < 0){
          perror("read");
          break;
      }
      ch[rc] = '\0';
      printf("%s\n", ch);
      if(!strcmp(ch, "ADD")){
        pthread_create(&tid, NULL, reader, NULL);
            pthread_join(tid, &ret_vpr);
        printf("%s\n", (char *) ret_vpr);
      }
    }
    close(data_socket);
    return 0;
}

При запуске возникает непредсказуемая ошибка сегмента проэкт. Сначала должен быть запущен сервер, а затем клиент. Я думаю, что проблема на стороне клиента, когда программа хочет выполнить printf ("% s \ n", (char *) ret_vpr); .

1 Ответ

0 голосов
/ 21 марта 2020

Я вообще не пытаюсь запустить программу из вашего кода, но ваша проблема может быть в следующих двух строках в неправильном порядке

pthread_cond_wait(&cnd, &mutex);
pthread_mutex_lock(&mutex);

это должно быть

pthread_mutex_lock(&mutex);
pthread_cond_wait(&cnd, &mutex);

так что читатель плохо синхронизирован

вы должны получить мьютекс, прежде чем вызывать pthread_cond_wait


[править] дополнительные замечания:

В писателе вы делаете :

char shm_data[70];
sprintf(shm_data, "%s -> %s", pack->data, pack->hash);
memcpy(shmp_wr, shm_data, strlen(shm_data));

во-первых, почему 70, а не DATA_LEN (+1), та же проблема в считывателе с размерами 32

во-вторых, вы уверены, что не пишете из shm_data и / или shmp_wr ?

наконец, вы не копируете нулевой символ, заканчивающий строку, в читателе вы делаете sscanf (shm_data, "% s ->% s", data, ha sh) и что нужен последний нулевой символ

Также очень странно делать

    int i = pthread_create(&tid, NULL, reader, NULL);

и сразу после

    i = pthread_join(tid, &ret_vpr);

просто выполнять работу в текущем потоке


[редактировать с вашей последней версии]

Функция reader возвращает адрес t Он локальный переменная пакет , вне функции, на которую нельзя ссылаться по адресу без неопределенного поведения. Но вы используете его в

printf("%s\n", (char *) ret_vpr);

Выделите pack в куче, а не поместите его в стек в reader . Конечно, в случаях ошибки возвращают, например, NULL и проверяют, что ret_vpr не является NULL перед вызовом printf в main

После этих изменений Выполнение сервера и клиента:

$ ./server 
0:
Bruno
1:
Ben
2:
Zack
3:
Jack

$ ./client 
connected
ADD
Jack
ADD
Bruno
ADD
Ben
ADD
Zack
...