指针在不同的线程中得到错误的值

时间:2019-05-06 12:34:13

标签: c++ linux c++11

我正在编写一段代码来演示多线程共享内存的编写。

但是,我的代码得到了一个奇怪的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(核心)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 个答案:

答案 0 :(得分:2)

您忘记为创建的SHM段(http://man7.org/linux/man-pages/man2/shmget.2.html)指定访问权限:

  

值shmflg由以下组成:

     

...

     

除了上述标志之外, shmflg的最低有效9位还指定了授予所有者,组和其他人的权限。这些位与open(2)的mode参数具有相同的格式和相同的含义。当前,系统未使用执行权限。

更改

shmid = shmget(shmkey, SEG_SIZE, IPC_CREAT);

进入

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

现在对我有效:https://wandbox.org/permlink/Am4r2GBvM7kSmpdO


请注意,我仅使用线程向量(无共享指针),如注释中其他建议。您也可以reserve它的空间。

答案 1 :(得分:2)

您忘记了一个非常重要事项:错误处理!

shmgetshmat函数都可能失败。如果失败,则返回值-1

现在,如果您查看第一个base_ptr值,则为0x5eebff。恰好与FRAME_SIZE - 1相同(FRAME_SIZE0x5eec00)。这意味着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的二进制补码十六进制表示法,并将其传递给创建的第一个线程。