我正在处理一个需要使用特定操作系统抽象的项目,我需要使用他们的信号量和互斥锁实现一个读写器锁。我目前有一个格式设置:
$var = $var.replace(/([~!@#$%^&*()-_+=`{}\[\]\|\\:;'<>,.\/? ])+/g, '-').replace(/^(-)+|(-)+$/g,'');
在这个实现中,我需要使用这种解锁方法解锁编写器并释放所有读取器信号量插槽,或者简单地释放读取器信号量插槽,但是,我正在努力,因为我无法想到一个实现,这将是在所有情况下工作。如何在给定的设置中完成这项工作?我知道POSIX能够在其实现中实现通用解锁方法是可能的,但是我找不到任何关于如何完成的指示,所以会欣赏人们可以共享的任何信息。
请注意,我不能使用C ++ 11或其他操作系统原语。
答案 0 :(得分:2)
好吧,定义两个函数UnlockRead
和UnlockWrite
。
我相信你不需要在同一个地方同时进行两次访问(写/读)。所以我建议的是另外两个类用于锁定访问:
class ReadWriteAccess
{
public:
ReadWriteAccess(uint32_t maxReaders);
~ReadWriteAccess();
uint32_t GetMaxReaders() const;
uint32_t GetMaxReaders() const;
eResult GetReadLock(int32_t timeout);
eResult GetWriteLock(int32_t timeout);
eResult UnlockWrite();
eResult UnlockRead();
private:
uint32_t m_MaxReaders;
Mutex* m_WriterMutex;
Semaphore* m_ReaderSemaphore;
};
并且具有用于读取和写入锁定的单独类,并且使用RAII始终保持安全:
class ReadLock
{
public:
ReadLock(ReadWriteAccess& access, int32_t timeout) : access(access)
{
result = access.GetReadLock(timeout);
}
eResult getResult() const { return result; }
~ReadLock()
{
if (result)
access.UnlockRead();
}
private:
ReadWriteAccess& access;
eResult result;
};
并使用如下:
T someResource;
ReadWriteAccess someResourceGuard;
void someFunction()
{
ReadLock lock(someResourceGuard);
if (lock.getResult())
cout << someResource; // it is safe to read something from resource
}
当然,您可以轻松地为WriteLock
由于OP坚持在评论中有“一个”解锁 - 请考虑缺点:
假设它实现了某种最后一次锁定函数的堆栈:
class ReadWriteLock
{
public:
ReadWriteLock(uint32_t maxReaders);
~ReadWriteLock();
uint32_t GetMaxReaders() const;
eResult GetReadLock(int32_t timeout)
{
eResult result = GetReadLockImpl(timestamp);
if (result)
lockStack.push(READ);
}
eResult GetWriteLock(int32_t timeout)
{
eResult result = GetWriteLockImpl(timestamp);
if (result)
lockStack.push(WRITE);
}
eResult Unlock()
{
LastLockMode lockMode = lockStack.top();
lockStack.pop();
if (lockMode == READ)
UnlockReadImpl();
else
UnlockWriteImpl();
}
private:
uint32_t m_MaxReaders;
Mutex* m_WriterMutex;
Semaphore* m_ReaderSemaphore;
enum Mode { READ, WRITE };
std::stack<Mode> lockStack;
};
但上述内容仅适用于单线程应用程序。并且单线程应用程序永远不需要任何锁定。
所以 - 你必须有多线程堆栈 - 比如:
template <typename Value>
class MultiThreadStack
{
public:
void push(Value)
{
stackPerThread[getThreadId()].push(value);
}
Value top()
{
return stackPerThread[getThreadId()].top();
}
void pop()
{
stackPerThread[getThreadId()].pop();
}
private:
ThreadId getThreadId() { return /* your system way to get thread id*/; }
std::map<ThreadId, std::stack<Value>> stackPerThread;
};
所以在MultiThreadStack
中使用这个ReadWriteLock
而不是std :: stack。
但是,上面的std::map
需要ReadWriteLock
才能锁定多个线程对它的访问权限 - 所以,在你开始使用它之前要么知道所有线程东西(预注册)或你最终遇到与here描述的问题相同的问题。所以我的建议 - 如果可以 - 改变你的设计。
答案 1 :(得分:1)
成功获取锁定时,类型是已知的:要么您有许多读者正在运行,要么只有一个作者,您不能让读者和作者都使用有效获取的锁定运行。
因此,当#include<stdio.h>
#include<stdlib.h>
#define MAX 100
int main()
{
int array*,i,n;
printf("Enter size of array:\n");
scanf("%d",&n);
array = malloc(n*sizeof(int));
/* code to enter numbers in array */
array += n;
//remember to free pointers after you are done with them
free(array);
return 0;
}
调用成功并且所有后续lock
调用(在提供读取许可的情况下可能很多,只有在请求写入锁定时才有一个)时,存储当前锁定模式就足够了属于那种模式。