c++ - 命名共享内存 : shm_open not providing the correct location

标签 c++ c linux shared-memory

我在使用共享内存时遇到困难。我相信我误解了共享内存应该如何工作。我正在尝试为我的项目创建一个模板类来包装 POSIX 共享内存 API。当我在同一个进程中第二次调用 mmap() 时,我希望看到返回的 ptr 与第一次相同。这不是我所看到的。我的第二个地址偏移了 0x1000(我假设这是页面边界)。当我写入第一个内存映射位置时,数据没有出现在第二个中。

我想可能是数据没有同步,所以我尝试调用 msync()。这没有帮助。

我最怀疑 mmap() 返回的不同地址。看起来这可能是一个指针指针,但没有文档或示例显示任何关于指针指针的信息。所以……

显然,这让我相信要么我做错了什么,要么误解了命名共享内存在同一进程中的工作方式。

我一直在倾注 man pages到处寻找答案无济于事。

有人能告诉我我在做什么来访问同名共享内存位置吗?或者指出我的回答,提供我需要的解释,让我再次上路。

请原谅所有的调试计算和过多的文档,我试图理解/学习 shared_memory API。

注意: 我知道有更好的方法可以在同一进程中共享数据。但是,这只是一个简短的测试驱动程序,该模板将用于多进程环境。

编辑:我不确定这是否重要,但我正在尝试在 Suse Linux 3.0.101 上运行



“帮我欧比旺克诺比,你是我唯一的希望!”

/p>

shmem.h

// ****************************************************************************
// POSIX Shared Memory
//     as document by Richard Stevens 
//     "UNIX Network Programming: Interprocess Communications" Vol 2, 2nd Ed.
// -------------------
//
// Shared memory is the fastest form of IPC available, because one copy of the
// data in the shared memory is available to all the threads or processes that
// share the memory. Some form of synchronization is normally required,
// however, to coordinate the threads or processes that are sharing the memory.
//
// POSIX provides two ways to share memory between unrelated processes.
//      1. Memory-mapped files: a file is opened by open, and the resulting
//         descriptor is mapped into the address space of the process by mmap.
//         Memory-mapped files can also be shared between unrelated processes.
//      2. Shared memory objects: the function shm_open opens a POSIX IPC name
//         (perhaps a pathname in the filesystem), returning a descriptor that
//         is then mapped into the address space of the process by mmap.
//
// Both techniques require the call to mmap. What differs is how the descriptor
// that is an argument to mmap is obtained: by open or shm_open.
//
// ****************************************************************************
#ifndef SHMEM_H_
#define SHMEM_H_

#include <errno.h>      // error checking
#include <fcntl.h>      // O_ constants
#include <semaphore.h>  // semaphore API
#include <stddef.h>     // defines NULL
#include <sys/mman.h>   // shared memory API
#include <sys/stat.h>   // mode constants
#include <unistd.h>     // for close()

#include <iostream>
using namespace std;

template <class T, long count = 1>
class shmem
{
public:

    // ------------------------------------------------------------------------
    shmem(const char* name) :
        pName(name), pShmData(0), mShmFd(0), mCreated(true)
    {
        cout << "START: shmem(\"" << pName << "\", " << count << ") Constructor" << endl<< flush;

        // --------------------------------------------------------------------
        // The two-step process involved with POSIX shared memory requires:
        //      1. calling shm_open, specifying a name argument, to either
        //         create a new shared memory object or to open an existing
        //         shared memory object, followed by
        //      2. calling mmap to map the shared memory into the address space
        //         of the calling process.
        int    flags = O_RDWR|O_CREAT|O_EXCL;
        mode_t mode  = S_IRUSR|S_IWUSR;

        // flag indicating that the shared memory is the same as the data
        // passed in
        bool valid = true;

        // Determine the amount of memory should include the
        // header + the data buffer
        const size_t len = sizeof(shmem_data_t);

        cout << "Shmem_open()... "<< flush;
        mShmFd = shm_open(pName, flags, mode);

        // Check to see if the shared memory has been created yet
        if (mShmFd == -1)
        {
            cout << "failed. ********************* errno: " << errno << endl<< flush;

            // Remove flags (O_EXCL, O_CREAT) and try to open shared memory
            // that already exists
            flags &= ~O_EXCL;
            flags &= ~O_CREAT;

            cout << "Shmem_open (Again)... "<< flush;
            mShmFd = shm_open(pName, flags, mode);

            // Check to see if an error occurred while trying to open
            valid = (mShmFd != -1);

            if (valid)
                        {
                cout << "success!" << endl<< flush;

                            // Indicate that the shared memory already existed
                            mCreated = false;
                        }
            else
                        {
                cout << "failed. ********************* errno: " << errno << endl<< flush;
                        }

        } else
        {
            cout << "success!" << endl << flush;
        }

        cout << "mmap()... "<< flush;
        // The mmap function maps a POSIX shared memory object (T) + Header
        // into the address space of a process.
        pShmData = reinterpret_cast<shmem_data_t*> (
                mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, mShmFd, 0));

        if (pShmData == NULL)
        {
            int error = errno;

            switch (error)
            {
            default:
                // Undefined Error
                cout << "failed: ********************* errno: " << error << endl<< flush;
                break;
            }
        } else
        {
            cout << "success: " << hex << "0x" << pShmData << dec << endl << flush;
        }

        // Check to see if we are the first user to request this shared memory
        // location.
        if (mCreated)
        {
            cout << "CREATED!" << endl;
            cout << "Initial Header Data: Size  " << pShmData->size  << endl;
            cout << "Initial Header Data: Count " << pShmData->len << endl;

            // Initialize the header if we created the SHM
            cout << "sem_init()" << endl<< flush;
            sem_init(&pShmData->mutex,1,1);

            cout << "sem_wait()... " << endl<< flush;
            sem_wait(&pShmData->mutex);

            cout << "Got It!" << endl<< flush;
            pShmData->size  = len;
            pShmData->len = count;

            cout << "release semaphore" << endl<< flush;
            sem_post(&pShmData->mutex);
            cout << "Initialization complete" << endl<< flush;

            cout << "Header Data: Size  " << pShmData->size  << endl;
            cout << "Header Data: Count " << pShmData->len << endl;

        } else if (valid)
        {

            cout << "Validating Shared Memory... " ;

            // Validate the Shared Memory that was acquired
            valid &= (pShmData->size == len);
            valid &= (pShmData->len == count);

            if (valid)
                cout << "success!" << endl<< flush;
            else
                cout << "failed. ********************* " << endl<< flush;

            cout << "Header Data: Size  " << pShmData->size  << endl;
            cout << "Header Data: Count " << pShmData->len << endl;


        }
else
{
shm_unlink(pName);
exit(1);
}

                // FIXME: What should we do if we aren't valid?!
        cout << "END: Shmem Constructor" << endl<< flush;

    }

    // ------------------------------------------------------------------------
    // Copy Constructor - Increment Use count for Shared Memory.
    shmem(const shmem& that) :
        pName(that.pName), pShmData(0), mShmFd(0)
    {
        cout << "START: shmem Copy Constructor" << endl << flush;

        // --------------------------------------------------------------------
        // The two-step process involved with POSIX shared memory requires:
        //      1. calling shm_open, specifying a name argument, to either
        //         create a new shared memory object or to open an existing
        //         shared memory object, followed by
        //      2. calling mmap to map the shared memory into the address space
        //         of the calling process.
        int    flags = O_RDWR;
        mode_t mode  = S_IRUSR|S_IWUSR;

        // flag indicating that the we allocated valid shared memory is the
        // same as the data passed in
        bool valid = true;

        // Determine the amount of memory should include the
        // header + the data buffer
        const size_t len = sizeof(shmem_data_t);

        mShmFd = shm_open(pName, flags, mode);

        // Check to see if an error occurred while trying to open
        valid = (mShmFd != -1);

        // The mmap function maps a POSIX shared memory object (T) + Header
        // into the address space of a process.
        pShmData = mmap(NULL, that.mShmFd->size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, mShmFd, 0);

        cout << "close()... "<< flush;
        // The close() function will deallocate the file descriptor.
        // All outstanding record locks owned by the process on the file
        // associated with the file descriptor will be removed (that is,
        // unlocked).
        //
        // If a shared memory object remains referenced at the last close (that is, a
        // process has it mapped), then the entire contents of the memory object persist
        // until the memory object becomes unreferenced. If this is the last close of a
        // memory object and the close results in the memory object becoming
        // unreferenced, and the memory object has been unlinked, then the memory object
        // will be removed.
        close(mShmFd);
        cout << "success." << endl<< flush;


        cout << "END: shmem Copy Constructor" << endl << flush;

    }


    // ------------------------------------------------------------------------
    virtual ~shmem()
    {

        cout << "START: ~shmem() Destructor" << endl<< flush;

                if (mCreated)
                {
        cout << "shm_unlink( \"" << pName << "\")... "<< flush;

        // The shm_unlink function removes the name of a shared memory object.
        // As with all the other unlink functions, unlinking a name has no
        // effect on existing references to the underlying object, until all
        // references to that object are closed. Unlinking a name just prevents
        // any subsequent call to open, mq_open, or sem_open from succeeding.
        if(shm_unlink(pName) == -1)
        {
            int error = errno;

            switch (error)
            {
            case EACCES:
                // Permission is denied to unlink the named shared memory
                // object.
                cout << "Failed: ********************* EACCES " << endl<< flush;
                break;

            case ENAMETOOLONG:
                // The length of the name argument exceeds {PATH_MAX} or a
                // pathname component is longer than {NAME_MAX}.
                cout << "Failed: ********************* ENAMETOOLONG" << endl<< flush;
                break;

            case ENOENT:
                // The named shared memory object does not exist.
                cout << "Failed: ********************* ENOENT" << endl<< flush;
                break;

            default:
                // Undefined Error
                cout << "Failed: ********************* <UNKNOWN> errno: " << error << endl<< flush;
                break;
            }
        } else
        {
            cout << "Success!" << endl<< flush;
        }

                }

        cout << "close()... " << flush;
        // The close() function will deallocate the file descriptor.
        // All outstanding record locks owned by the process on the file
        // associated with the file descriptor will be removed (that is,
        // unlocked).
        //
        // If a shared memory object remains referenced at the last close (that is, a
        // process has it mapped), then the entire contents of the memory object persist
        // until the memory object becomes unreferenced. If this is the last close of a
        // memory object and the close results in the memory object becoming
        // unreferenced, and the memory object has been unlinked, then the memory object
        // will be removed.
        close(mShmFd);
        cout << "success." << endl << flush;



        cout << "END: ~shmem() Destructor" << endl<< flush;
    }


    // ------------------------------------------------------------------------
    // Returns address only to the indexed object in shared memory
    T* Obj_Addr(uint32_t n = 0)
    {
        cout << "shmem.Obj_Addr()" << endl << flush;
        return &pShmData->buf[n];
    }

    // ------------------------------------------------------------------------
    // sync...
    void Sync()
    {
                cout << "shmem.Sync()... ";
               if (msync(pShmData, sizeof(shmem_data_t), MS_SYNC) == -1)
               {
                   cout << "failed: ********************* errno: " << errno << endl<< flush;
               } else
               {
                   cout << "success. " << endl << flush;
               }        
    }

    // ------------------------------------------------------------------------
    // Returns reference only to the indexed object in shared memory
    T& Obj(uint32_t n = 0)
    {
        cout << "shmem.Obj()" << endl << flush;
        return pShmData->buf[n];
    }

    // ------------------------------------------------------------------------
    // Returns reference only to the indexed object in shared memory
    T& operator[] (uint32_t n)
    {
        cout << "Accessing shmem[" << n << "] == " << flush;
        cout << pShmData->buf[n] << "!"  << endl << flush;
        return pShmData->buf[n];
    }


private:
    // ------------------------------------------------------------------------
    // Hide default constructor
    shmem() : pName(0), pShmData(0), mShmFd(0)
    {

    }

private:
    struct shmem_data_t
    {
        size_t   size;
        uint32_t len;
        sem_t    mutex;
        T        buf[count];
    };

    const char*   pName;
    shmem_data_t* pShmData;
    int           mShmFd;
        // Flag indicating that we created the shared memory
bool mCreated;


};

#endif /* SHMEM_H_ */

main.cpp

#include <signal.h>
#include <stdlib.h>
#include <string.h>

#include <iostream> // ** FIXME ** DEBUG
using namespace std;

#include "stdint.h"
#include "shmem.h"

bool done = false;

// ----------------------------------------------------------------------------
void my_handler(int s)
{
          cout << "Goodbye! SIG: " << s << endl << flush;
          done = true;
}

// ----------------------------------------------------------------------------
void test_shmem()
{

    cout << endl << endl << "Testing Shmem Template" << endl;
    cout << "-------------------------------------------" << endl;
    shmem<int,13> x("/jco");
    cout << "-------------------------------------------" << endl;
    shmem<int,13> y("/jco");
    cout << "-------------------------------------------" << endl;
    x[5] = 7;
        x.Sync();
    cout << "-------------------------------------------" << endl;
    cout << "X[5] = " << x[5] << endl;
    cout << "-------------------------------------------" << endl;
    cout << "Y[5] = " << y[5] << endl;
    cout << "-------------------------------------------" << endl;
    cout << endl << "*** Testing Complete." << endl << endl;

    sleep(10);

}

// ----------------------------------------------------------------------------
int main()
{
    cout << "MAIN" << endl;

   struct sigaction sigIntHandler;

   sigIntHandler.sa_handler = my_handler;
   sigemptyset(&sigIntHandler.sa_mask);
   sigIntHandler.sa_flags = 0;

   sigaction(SIGINT, &sigIntHandler, NULL);


    test_shmem();

    // RUN
    while(not done)
    {
        sleep(1);
    }

    return 0;
}

控制台输出:

MAIN


Testing Shmem Template
-------------------------------------------
START: shmem("/jco", 13) Constructor
Shmem_open()... success!
mmap()... success: 0x0x7f32113ad000
CREATED!
Initial Header Data: Size  0
Initial Header Data: Count 0
sem_init()
sem_wait()...
Got It!
release semaphore
Initialization complete
Header Data: Size  104
Header Data: Count 13
END: Shmem Constructor
-------------------------------------------
START: shmem("/jco", 13) Constructor
Shmem_open()... failed. ********************* errno: 17
Shmem_open (Again)... success!
mmap()... success: 0x0x7f32113ac000
Validating Shared Memory... failed. *********************
Header Data: Size  0
Header Data: Count 0
END: Shmem Constructor
-------------------------------------------
Accessing shmem[5] == 0!
shmem.Sync()... success.
-------------------------------------------
Accessing shmem[5] == 7!
X[5] = 7
-------------------------------------------
Accessing shmem[5] == 0!
Y[5] = 0
-------------------------------------------

*** Testing Complete.

START: ~shmem() Destructor
close()... success.
END: ~shmem() Destructor
START: ~shmem() Destructor
shm_unlink( "/jco")... Success!
close()... success.
END: ~shmem() Destructor
Goodbye! SIG: 2

最佳答案

编辑:我的第一个回答完全没有达到要求。所以我觉得有义务贡献一些有用的东西。

Petesh 和 BЈовић 都给出了正确的答案。首先,您不应该使用 MAP_ANONYMOUS。其次,您应该意识到您从 mmap 返回的(虚拟)地址将与第一个地址不同。当您两次调用 mmap 时,您将创建两个单独的映射到同一共享内存。但是您可以使用这两个地址中的任何一个,它们将指向同一 block 共享内存。

我写了这个小程序来演示。它基本上执行您的程序执行的操作,并表明即使两个 mmap 调用返回两个不同的地址,这两个地址都在读取和写入同一共享内存。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#define TEMP_FILENAME   "shm.tmp"

int main(void)
{
    int fd1 = shm_open(TEMP_FILENAME, O_CREAT | O_RDWR, 0777);
    int fd2 = shm_open(TEMP_FILENAME, O_RDWR, 0777);
    int *p1, *p2;
    int buf[1024] = {0x12345678};

    // Write initial contents to shared memory.
    write(fd1, buf, 4096);
    p1 = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, 0);
    p2 = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd2, 0);
    printf("fd1 = %d, p1 = %p\n", fd1, p1);
    printf("fd2 = %d, p2 = %p\n", fd2, p2);
    printf("p1[0] = 0x%08x, p2[0] = 0x%08x\n", p1[0], p2[0]);
    p1[0] = 0xdeadbeef;
    printf("p1[0] = 0x%08x, p2[0] = 0x%08x\n", p1[0], p2[0]);
    close(fd2);
    close(fd1);
    shm_unlink(TEMP_FILENAME);
    return 0;
}

输出:

fd1 = 3, p1 = 0x7f2b3d434000
fd2 = 4, p2 = 0x7f2b3d433000
p1[0] = 0x12345678, p2[0] = 0x12345678
p1[0] = 0xdeadbeef, p2[0] = 0xdeadbeef

关于c++ - 命名共享内存 : shm_open not providing the correct location,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27325123/

相关文章:

C++ 二维集成库

c - 如何计算 malloc 分配的内存块的结束地址?

linux - 什么时候进程上下文切换应该比线程上下文切换更快?

linux - APUE2中的一个困惑(关于UNIX中的symbolic link)

c - 捕获实时流量时如何开启纳秒精度?

c++ - NumPy 的 C++ : How to iterate over PyArrayObject without a segfault

c++ - 围绕相机旋转 opengl c++/设置旋转中心

c - 输出 unicode wchar_t 字符

c++ - 在没有着色器的情况下在 OpenGL 中渲染深度缓冲区

c - 如何使用__malloc_hook?