указатель получить неверное значение в другом потоке - PullRequest
0 голосов
/ 06 мая 2019

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

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

Я компилирую с помощью команды: g++ --std=c++11 shared_mem_multi_write.cpp -lpthread -g

Я получаю эхо-ошибки типа:

function base_ptr: 0x5eebff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0xffffffffffffffff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0xbdd7ff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0x23987ff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0x11cc3ff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0x17bafff, src_ptr: 0x7f21a9c4e010, size: 6220800
function base_ptr: 0x1da9bff, src_ptr: 0x7f21a9c4e010, size: 6220800
Segmentation fault (core dumped)

Моя ОС - это CentOS Linux выпуск 7.6.1810 (Core) gcc версии 4.8.5, код которого приведен ниже:

#include <chrono>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <thread>
#include <vector>
#include <memory>

const size_t THREAD_CNT = 40;
const size_t FRAME_SIZE = 1920 * 1080 * 3;
const size_t SEG_SIZE = FRAME_SIZE * THREAD_CNT;

void func(char *base_ptr, char *src_ptr, size_t size)
{
    printf("function base_ptr: %p, src_ptr: %p, size: %u\n", base_ptr, src_ptr, size);
    while (1)
    {
        auto now = std::chrono::system_clock::now();
        memcpy(base_ptr, src_ptr, size);
        std::chrono::system_clock::time_point next_ts =
            now + std::chrono::milliseconds(42); // 24 frame per seconds => 42 ms per frame
        std::this_thread::sleep_until(next_ts);
    }
}

int main(int argc, char **argv)
{
    int shmkey = 666;
    int shmid;
    shmid = shmget(shmkey, SEG_SIZE, IPC_CREAT);
    char *src_ptr = new char[FRAME_SIZE];
    char *shmpointer = static_cast<char *>(shmat(shmid, nullptr, 0));
    std::vector<std::shared_ptr<std::thread>> t_vec;
    t_vec.reserve(THREAD_CNT);
    for (int i = 0; i < THREAD_CNT; ++i)
    {
        //t_vec[i] = std::thread(func, i * FRAME_SIZE + shmpointer, src_ptr, FRAME_SIZE);
        t_vec[i] = std::make_shared<std::thread>(func, i * FRAME_SIZE + shmpointer, src_ptr, FRAME_SIZE);
    }
    for (auto &&t : t_vec)
    {
        t->join();
    }
    return 0;
}

Ответы [ 2 ]

2 голосов
/ 06 мая 2019

Вы забыли одну очень важную вещь: Обработка ошибок!

Обе функции shmget и shmat могут не работать.Если они терпят неудачу, они возвращают значение -1.

Теперь, если вы посмотрите на первое base_ptr значение, это 0x5eebff.Это просто так же, как FRAME_SIZE - 1 (FRAME_SIZE это 0x5eec00).Это означает, что shmat do возвращает -1 и не удалось.

Поскольку вы продолжаете использовать это ошибочное значение, все ставки выключены.

Вам необходимопроверьте наличие ошибок и, если это произойдет, выведите значение errno, чтобы узнать, что пошло не так:

void* ptr = shmat(shmid, nullptr, 0);
if (ptr == (void*) -1)
{
    std::cout << "Error getting shared memory: " << std::strerror(errno) << '\n';
    return EXIT_FAILURE;
}

Сделайте что-то подобное для shmget.

Теперь это также легкочтобы понять значение 0xffffffffffffffff.Это шестнадцатеричная запись дополнения к двум для -1, и она передается первому созданному потоку.

2 голосов
/ 06 мая 2019

Вы забыли указать права доступа для созданного сегмента SHM (http://man7.org/linux/man-pages/man2/shmget.2.html):

Значение shmflg состоит из:

...

В дополнение к указанным выше флагам, младшие 9 битов shmflg указывают разрешения, предоставленные владельцу, группе и другим . Эти биты имеют тот же формат и то же значение, что и аргумент mode open (2). В настоящее время разрешения на выполнение не используются системой.

Изменение

shmid = shmget(shmkey, SEG_SIZE, IPC_CREAT);

в

shmid = shmget(shmkey, SEG_SIZE, IPC_CREAT | 0666);

У меня сейчас работает: https://wandbox.org/permlink/Am4r2GBvM7kSmpdO


Обратите внимание, что я использую только вектор потоков (без общих указателей), как это предлагается в комментариях. Вы также можете reserve его пространство.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...