C+中的系统范围全局变量/信号量/互斥体+/Linux? 在Linux上可以在C++上创建一个系统范围的全局变量/信号量/互斥体吗?p>

C+中的系统范围全局变量/信号量/互斥体+/Linux? 在Linux上可以在C++上创建一个系统范围的全局变量/信号量/互斥体吗?p>,c++,linux,concurrency,mutex,semaphore,C++,Linux,Concurrency,Mutex,Semaphore,原因是:我有一个系统,经常在不相关的数据上运行同一软件的多个副本。通常有4个作业,每个作业运行相同的软件。该软件有一个小的部分,它创建了一个巨大的图形,需要大量的内存;除此之外,内存使用是适度的 有时,两个作业同时命中同一个内存不足的部分,整个系统开始交换。因此,我们希望通过在不同作业之间创建类似于临界段互斥的东西来防止这种情况,这样一来,一次最多只能有一个作业分配大量内存 如果这些是同一作业的线程,则pthread锁将执行该作业 在不同的作业之间实现这种互斥的好方法是什么?如果可以让所有进程都

原因是:我有一个系统,经常在不相关的数据上运行同一软件的多个副本。通常有4个作业,每个作业运行相同的软件。该软件有一个小的部分,它创建了一个巨大的图形,需要大量的内存;除此之外,内存使用是适度的

有时,两个作业同时命中同一个内存不足的部分,整个系统开始交换。因此,我们希望通过在不同作业之间创建类似于临界段互斥的东西来防止这种情况,这样一来,一次最多只能有一个作业分配大量内存

如果这些是同一作业的线程,则pthread锁将执行该作业

在不同的作业之间实现这种互斥的好方法是什么?

如果可以让所有进程都同意一个通用名称,那么可以使用

命名信号量由表单的名称标识
/somename
;也就是说,以null结尾的字符串最多为 名称\u MAX-4(即251)个字符,由首字母组成 斜杠,后跟一个或多个字符,其中没有一个字符是 砍两个进程可以在同一个名称上运行 通过将相同名称传递给
sem\u open(3)
来发送信号量

互斥锁(互斥锁)防止多个线程同时执行访问共享数据的关键代码段(即互斥锁用于序列化线程的执行)。所有互斥体都必须是全局的。通过
mutex\u lock()
成功调用互斥锁将导致另一个试图锁定同一互斥锁的线程阻塞,直到所有者线程通过
mutex\u unlock()
将其解锁。同一进程内或其他进程内的线程可以共享互斥锁

互斥体可以同步同一进程中的线程其他进程中的线程。如果互斥体在可写内存中分配并在协作进程之间共享(请参见
mmap(2)
),并且已为此任务初始化,则互斥体可用于在进程之间同步线程

对于进程间同步,需要在这些进程之间共享的内存中分配互斥。由于必须动态分配此类互斥体的内存,因此需要使用
mutex\u init()
显式初始化互斥体。
此外,对于进程间同步,除了在共享内存中分配的要求外,互斥体还必须使用属性
PTHREAD\u process\u shared
,否则从其创建者以外的另一个进程访问互斥体会导致未定义的行为(参见此:):“进程共享属性设置为
PTHREAD\u process\u shared
,以允许访问分配互斥体的内存的任何线程对互斥体进行操作,即使互斥体是在多个进程共享的内存中分配的。“

对于进程间互斥,可以使用文件锁定。对于linux,代码非常简单,只需通过调用来保护关键部分


如果需要POSIX兼容性,可以使用.< /p>,可以使C++互斥体在Linux上跨进程边界工作。然而,其中涉及到一些黑魔法,这使得它不太适合于生产代码

说明: 标准库的
std::mutex
std::shared_mutex
在引擎盖下使用pthread的
struct pthread_mutex
pthread_rwlock\t
native\u handle()
方法返回指向这些结构之一的指针

缺点是某些细节从标准库中抽象出来,并在实现中默认。例如,
std::shared_mutex
通过将
NULL
作为第二个参数传递给
pthread\u rwlock\u init()
来创建其底层的
pthread\u rwlock\u t
结构。这应该是指向
pthread\u rwlockattr\u t
结构的指针,该结构包含确定共享策略的属性

公共:
__共享互斥线程
{
int_uuret=pthread_rwlock_init(&_M_rwlock,NULL);
...
理论上,它应该接收默认属性

进程共享属性的默认值是PTHREAD_process_PRIVATE

也就是说,std::shared_mutex和std::mutex都可以跨进程工作。我使用的是Clang 6.0.1(x86_64-unknown-linux-gnu/POSIX线程模型)。下面是我检查的说明:

  • 使用
    shm\u open
    创建共享内存区域

  • 使用
    fstat
    检查区域的大小以确定所有权。如果
    .st\u size
    为零,则
    ftruncate()
    调用方知道这是区域的创建过程

  • 在上面调用
    mmap

    • 创建者进程使用placement-
      new
      在共享区域内构造
      std::mutex
      std::shared_mutex
      对象
    • 以后的进程使用
      重新解释\u cast()
      获取指向同一对象的类型指针
  • 这些进程现在每隔一段时间调用
    trylock()
    unlock()
    。您可以看到它们在
    trylock()
    之前和之后以及
    unlock()
    之前使用
    printf()
    互相阻塞

额外细节:我对C++头文件或pTrices实现是否有错,所以我挖掘到<代码> pthRead RWLKORKARCHYTU< <代码>。你会发现一个<代码>共享的< /COD>属性是0和一个代码>

int fd_lock = open(LOCK_FILE, O_CREAT);

flock(fd_lock, LOCK_EX);

// do stuff

flock(fd_lock, LOCK_UN);
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>

using std::string;

//from the command line - "ls /dev/shm" and "lsof /dev/shm/<name>" to see which process ID has access to it

template<typename PAYLOAD>
class InterprocessSharedVariable
{
protected:
    int mSharedMemHandle;
    string const mSharedMemoryName;
    bool mOpenedMemory;
    bool mHaveLock;
    pid_t mPID;

    // this is the shared memory structure
    typedef struct 
    {
        pid_t mutex;
        PAYLOAD payload;
    }
    tsSharedPayload;


    tsSharedPayload* mSharedData;


    bool openSharedMem()
    {
        mPID = getpid();

        // The following caters for the shared mem being created by root but opened by non-root,
        //  giving the shared-memory 777 permissions.
        int openFlags = O_CREAT | O_RDWR;
        int shareMode = S_IRWXU | S_IRWXG | S_IRWXO;

        // see https://stackoverflow.com/questions/11909505/posix-shared-memory-and-semaphores-permissions-set-incorrectly-by-open-calls
        // store old
        mode_t old_umask = umask(0);

        mSharedMemHandle = shm_open (mSharedMemoryName.c_str(), openFlags, shareMode);

        // restore old
        umask(old_umask);

        if (mSharedMemHandle < 0) 
        {
            std::cerr << "failed to open shared memory"  << std::endl;
            return false;
        }

        if (-1 == ftruncate(mSharedMemHandle, sizeof(tsSharedPayload)))
        {
            std::cerr <<  "failed to resize shared memory" << std::endl;
            return false;
        }

        mSharedData = (tsSharedPayload*) mmap (NULL, 
                                            sizeof(tsSharedPayload),
                                            PROT_READ | PROT_WRITE,
                                            MAP_SHARED,
                                            mSharedMemHandle,
                                            0);

        if (MAP_FAILED == mSharedData)
        {
            std::cerr << "failed to map shared memory" << std::endl;
            return false;
        }

        return true;
    }


    void closeSharedMem()
    {
        if (mSharedMemHandle > 0)
        {
            mSharedMemHandle = 0;
            shm_unlink (mSharedMemoryName.c_str());
        }
    }

public:
    InterprocessSharedVariable () = delete;

    InterprocessSharedVariable (string const&& sharedMemoryName) : mSharedMemoryName(sharedMemoryName)
    {
        mSharedMemHandle = 0;
        mOpenedMemory = false;
        mHaveLock = false;
        mPID = 0;
    }

    virtual ~InterprocessSharedVariable ()
    {
        releaseSharedVariable ();
        closeSharedMem ();
    }

    // no copying
    InterprocessSharedVariable (InterprocessSharedVariable const&) = delete;
    InterprocessSharedVariable& operator= (InterprocessSharedVariable const&) = delete;


    bool tryLockSharedVariable (pid_t& ownerProcessID)
    {
        // Double-checked locking.  See if a process has already grabbed the mutex.  Note the process could be dead
        __atomic_load (&mSharedData->mutex, &ownerProcessID, __ATOMIC_SEQ_CST);

        if (0 != ownerProcessID)
        {
            // It is possible that we have started with the same PID as a previous process that terminated abnormally
            if (ownerProcessID == mPID)
            {
                // ... in which case, we already "have ownership"
                return (true);
            }

            // Another process may have the mutex.  Check whether it is alive.
            // We are specifically looking for an error returned with ESRCH
            // Note that if the other process is owned by root, "kill 0" may return a permissions error (which indicates the process is running!)
            int processCheckResult = kill (ownerProcessID, 0);

            if ((0 == processCheckResult) || (ESRCH != errno))
            {
                // another process owns the shared memory and is running
                return (false);
            }

            // Here: The other process does not exist ((0 != processCheckResult) && (ESRCH == errno))
            // We could assume here that we can now take ownership, but be proper and fall into the compare-exchange
            ownerProcessID = 0;
        }

        // It's possible that another process has snuck in here and taken ownership of the shared memory.
        // If that has happened, the exchange will "fail" (and the existing PID is stored in ownerProcessID)

        // ownerProcessID == 0 -> representing the "expected" value
        mHaveLock = __atomic_compare_exchange_n (&mSharedData->mutex,
                                                &ownerProcessID,      //"expected"
                                                mPID,                 //"desired"
                                                false,                //"weak"
                                                __ATOMIC_SEQ_CST,     //"success-memorder"
                                                __ATOMIC_SEQ_CST);    //"fail-memorder"

        return (mHaveLock);
    }


    bool acquireSharedVariable (bool& failed, pid_t& ownerProcessID)
    {
        if (!mOpenedMemory)
        {
            mOpenedMemory = openSharedMem ();

            if (!mOpenedMemory)
            {
                ownerProcessID = 0;
                failed = true;
                return false;
            }
        }

        // infrastructure is working
        failed = false;

        bool gotLock = tryLockSharedVariable (ownerProcessID);
        return (gotLock);
    }

    void releaseSharedVariable ()
    {
        if (mHaveLock)
        {
            __atomic_store_n (&mSharedData->mutex, 0, __ATOMIC_SEQ_CST);
            mHaveLock = false;
        }
    }
};
int main(int argc, char *argv[])
{
    typedef struct { } tsEmpty;
    InterprocessSharedVariable<tsEmpty> programMutex ("/run-once");

    bool memOpenFailed;
    pid_t ownerProcessID;
    if (!programMutex.acquireSharedVariable (memOpenFailed, ownerProcessID))
    {
        if (memOpenFailed)
        {
            std::cerr << "Failed to open shared memory" << std::endl;
        }
        else
        {
            std::cerr << "Program already running - process ID " << ownerProcessID << std::endl;
        }
        return -1;
    }

    ... do stuff ...

    return 0;
}