我有多个连续执行的函数。 第一个函数确定指向 ram 中某个位置的指针,如果该位置与另一个线程共享,它将调用互斥体的锁定函数。 第二个函数处理指针指向的数据,然后解锁资源。一旦程序执行 mtx.lock(),它就会被卡住,因此程序就会停止继续。我正在模拟一个 cpu 和一个简单的图形芯片,并尝试锁定两者访问的内存位置(cpu 和“gpu”在不同的线程上运行)。我试图防止同时访问内存中由上述两个线程访问的位置。 我为虚拟内存(数组)中的每个地址或地址范围都有一个互斥体。目前只有“cpu”线程锁定互斥量,它们尚未在 GPU 上实现,因此当“cpu”第一次执行锁定函数时无法锁定它们。
更准确地说,“cpu”在单独的线程上运行,而具有显示输出的“gpu”在主线程上运行。我不调用 thread_cpu.join(),以防出现错误(其中 thread_cpu 像
std::thread thread_cpu(cpu.run());
一样初始化)。
我的代码如下所示:
sync.h(包含在多个cpp文件中)
inline std::mutex mtx;
memory.cpp(返回指针并锁定互斥体,在使用指针处理后,互斥体通过 post_process 解锁)
#include "sync.h"
class Memory{
private:
UInt32* virtual_memory;
public:
Memory(){
virtual_memory = new UInt32[0x2000];
};
UInt32* get_address(UInt32 addr_virt){
mtx.lock();
return &virtual_memory[addr_virt];
}
void post_process(){
mtx.unlock();
}
}
实际上它更复杂,但这显示了互斥体是如何实现的。如何实现这一功能?
我(强烈)建议从一个简单的一般规则开始:不要直接锁定或解锁互斥锁。
相反,请养成使用类似
std::lock_guard
(或 std::scoped_lock
或 std::unique_lock
,具体取决于情况)之类的东西来锁定互斥锁的习惯,当离开锁定互斥锁的范围时,它会自动解锁互斥锁。
例如:
UInt32* get_address(UInt32 addr_virt){
std::lock_guard L(mtx);
return &virtual_memory[addr_virt];
}
如果需要调用多个期望互斥体自始至终都拥有的函数,请创建一个锁定互斥体的函数,然后按规定的顺序调用函数:
void foo() {
std::lock_guard L(mtx);
a(); // none of a(), b() or c() deals with the mutex at all.
b();
c();
}
不,您不能在一个线程中锁定互斥体,然后从另一个线程进行匹配的解锁。当一个线程锁定互斥锁时,该线程需要解锁该互斥锁。互斥体的全部意义在于确保在互斥体锁定时只有一个线程可以访问共享资源。如果一个线程锁定了互斥锁,而另一个线程解锁了它,那么这将颠覆使用互斥锁的整个目的。