Squeak.ru - шаблоны программирования

Проблема с общей памятью в C

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

Общая память. 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;
}

server.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;
}

клиент.с

#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;
}

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

21.03.2020

  • Почему вы используете потоки, если вы сериализуете их с помощью join сразу после create? В любом случае, позвольте мне попросить вас резко сократить это до минимального воспроизводимого примера. Возможно, запустите серверный процесс, который записывает свой pid в общую память, а затем вызываемый вручную клиентский процесс, который считывает его, пока сервер все еще работает. Затем, возможно, добавьте сокет IPC, чтобы координировать его. Тогда, возможно, добавьте темы, если вы думаете, что это что-то добавляет. Я подозреваю, что вы найдете свою проблему, если сделаете это. 23.03.2020
  • @pilcrow - я использую потоки, потому что мне нужно измерить пропускную способность всей программы, увеличив количество потоков. - Архитектура этой системы такова: сервер запускается и админ может добавить какие-то данные в его локальную таблицу. Через некоторое время к серверу подключается другой процесс, чтобы синхронизировать свою таблицу с таблицей сервера. таблица используется совместно через общую память, и любая операция на сервере с соответствующей таблицей сообщается другим процессам через их pid через сокет. одновременно сервер помещает новые добавленные данные или данные для удаления в общую память. 23.03.2020
  • С другой стороны, клиент получает код операции через сокет и понимает, что в общей памяти есть данные, которые должны быть добавлены или удалены в соответствии с операцией. 23.03.2020
  • Пожалуйста, сократите его до MRE, демонстрирующего только одну проблему. 23.03.2020

Ответы:


1

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

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, hash), и для этого нужен последний нулевой символ

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

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

и сразу после

    i = pthread_join(tid, &ret_vpr);

просто сделайте работу в текущем потоке


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

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

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
21.03.2020
  • не работал. в первой программе в разделяемую память записывается только первый узел связанного списка, а вторая программа может его прочитать. Другие узлы, которые должны быть записаны в разделяемую память, не записываются. Выбросы функции записи Не удалось создать общую память. 22.03.2020
  • @BenEslami В любом случае строки в неправильном порядке, и вы должны это исправить. Почему вы раньше не говорили об этой ошибке, вы надеялись, что мы сможем догадаться, о чем вы не говорите? Измените свою программу, чтобы записать значение errno, когда у вас есть эта ошибка, чтобы узнать причину, вы также можете использовать strerror и т. д. 22.03.2020
  • Я помещаю perror (ошибка) в функцию записи ниже строки printf (не удалось создать общую память\n); . Результат - недопустимый аргумент 22.03.2020
  • @BenEslami Я попросил вас указать значение errno (и может быть perror ), есть несколько возможностей иметь недопустимый аргумент. Каковы значения key? 22.03.2020
  • Значение ошибки: 22 22.03.2020
  • @BenEslami ты понимаешь, что тебе трудно помочь, пока ты каждый раз не отвечаешь на все вопросы? Я также спрашивал вас о key, это принудительно, если 22 также является EINVAL. Аргумент имени для shm_open() недействителен. для тебя 22.03.2020
  • значение ключа является глобальным значением: char *key = /shm; 22.03.2020
  • хорошо, проблема в том, что есть несколько других возможностей, включая недопустимый доступ к памяти, но многие определения/инициализации скрыты, нам нужен минимальный, полный, и Поддающийся проверке пример. Исходя из этого, почему вы используете pthread_create сразу после pthread_join, просто выполняйте работу в текущем потоке 22.03.2020
  • Этот проект предназначен для оценки пропускной способности за счет увеличения количества потоков. Я чувствую, что эта проблема связана с тем, что я запускаю ее на Mac OSX. 22.03.2020
  • @BenEslami Я отредактировал свой ответ, но снова нам нужен минимальный, полный и проверяемый пример, иначе невозможно помочь вам больше и ваш вопрос будет закрыт по этой причине, вероятно 22.03.2020
  • Я изучаю ваши подсказки, которые вы только что добавили в свой ответ. Кроме того, я только что добавил больше информации о проблеме в свой вопрос. 22.03.2020
  • @BenEslami - клиент и сервер - два разных процесса? если да, я не понимаю использование условия 22.03.2020
  • Да, это два разных процесса. Условие используется потому, что я не знал, что делать дальше. :)) 22.03.2020
  • @BenEslami уменьшите свой код, тем больше возможно воспроизвести проблему, а затем опубликуйте все это, я уже несколько раз просил вас предоставить минимальный, полный и Поддающийся проверке пример , пока вы этого не сделаете, я не буду тратить на вас больше времени, даже если я нахожусь в заключении из-за covid-19 ... 22.03.2020
  • Привет @bruno, я только что сделал то, что ты сказал раньше. 22.03.2020
  • @BenEslami да, это позволило мне найти, см. конец моего отредактированного ответа 23.03.2020
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...