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