网站建设288,动态视频素材网站,wordpress design,wordpress文章末尾广告位最近要写一个多线程的并发数据库#xff0c;主要是希望使用读写锁实现库的并发访问#xff0c;同时考虑到其他平台(如Iar)没有C的读写锁#xff0c;需要操作系统提供#xff0c;就将读写锁封装起来。整个过程还是比较曲折的#xff0c;碰到了不少问题#xff0c;在此就简… 最近要写一个多线程的并发数据库主要是希望使用读写锁实现库的并发访问同时考虑到其他平台(如Iar)没有C的读写锁需要操作系统提供就将读写锁封装起来。整个过程还是比较曲折的碰到了不少问题在此就简单分析总结下并发和互斥吧。 首先先贴上一部分源代码
#include shared_mutex
#include iostream
#include windows.h
#include synchapi.husing cegn_mutex std::shared_mutex;
cegn_mutex g_cegn_mutex;
void cegn_mutex_unique_lck(cegn_mutex testmutex) //独占锁写数据
{std::unique_lockcegn_mutex cegn_lock(testmutex);
}void cegn_mutex_share_lck(cegn_mutex Dbmutex) //共享锁读数据
{std::shared_lockcegn_mutex cegn_lock(Dbmutex);
}void cegn_mutex_unlck(cegn_mutex Dbmutex)
{; //vc读写锁离开作用域自动释放
}int g_dwVal 0;
void FastWriteData(int i)
{while (1){cegn_mutex_unique_lck(g_cegn_mutex);g_dwVal;std::cout FastWriteData Set dwVal g_dwVal \n;Sleep(1000);cegn_mutex_unlck(g_cegn_mutex);}
}void SlowWriteData(int i)
{while (1){cegn_mutex_unique_lck(g_cegn_mutex);g_dwVal;std::cout SlowWriteData Set dwVal g_dwVal \n;Sleep(5000);cegn_mutex_unlck(g_cegn_mutex);}
}void ReadData(int i)
{while (1){cegn_mutex_share_lck(g_cegn_mutex);std::cout ReadData Get dwVal g_dwVal \n;Sleep(500);cegn_mutex_unlck(g_cegn_mutex);}
}int main()
{std::cout main start !! std::endl;std::thread thread1 std::thread(FastWriteData, 0);std::thread thread2 std::thread(SlowWriteData, 0);thread1.join();thread2.join();getchar();return 1;
}
代码不长逻辑也挺清晰的但结果不正确 似乎就没有互斥保护因为FastWriteData和SlowWriteData中都独占了cegn_mutex_unique_lck(g_cegn_mutex);
且在while(1)中不存在释放写锁的情况那就不应该两个写线程交替出现。
如上让chatgpt分析下它认为没啥问题我尝试修改回标准读写锁接口如下
void FastWriteData(int i)
{while (1){
// cegn_mutex_unique_lck(g_cegn_mutex);std::unique_lockcegn_mutex lck(g_cegn_mutex);g_dwVal;std::cout FastWriteData Set dwVal g_dwVal \n;Sleep(1000);cegn_mutex_unlck(g_cegn_mutex);}
}void SlowWriteData(int i)
{while (1){
// cegn_mutex_unique_lck(g_cegn_mutex);std::unique_lockcegn_mutex lck(g_cegn_mutex);g_dwVal;std::cout SlowWriteData Set dwVal g_dwVal \n;Sleep(5000);cegn_mutex_unlck(g_cegn_mutex);}
} 如上代码运行就是正常了
main start !!
FastWriteData Set dwVal 1
FastWriteData Set dwVal 2
FastWriteData Set dwVal 3
FastWriteData Set dwVal 4
FastWriteData Set dwVal 5
FastWriteData Set dwVal 6
FastWriteData Set dwVal 7
FastWriteData Set dwVal 8
FastWriteData Set dwVal 9
FastWriteData Set dwVal 10
FastWriteData Set dwVal 11
FastWriteData Set dwVal 12
FastWriteData Set dwVal 13
FastWriteData Set dwVal 14
现在FastWriteData就独占了互斥量导致SlowWriteData无法运行。为啥使用接口
void cegn_mutex_unique_lck(cegn_mutex testmutex) //独占锁写数据 { std::unique_lockcegn_mutex cegn_lock(testmutex); }
就不行了
修改成直接调用
using cegn_mutex std::shared_mutex;
cegn_mutex g_cegn_mutex;
void cegn_mutex_unique_lck(cegn_mutex testmutex) //独占锁写数据
{
// std::unique_lockcegn_mutex cegn_lock(testmutex);std::unique_lockcegn_mutex cegn_lock(g_cegn_mutex);
}还是不能正确互斥修改如下也一样
void cegn_mutex_unique_lck(cegn_mutex testmutex) //独占锁写数据
{
// std::unique_lockcegn_mutex cegn_lock(testmutex);std::unique_lockstd::shared_mutex cegn_lock(g_cegn_mutex);
}
经过分析问题是
void cegn_mutex_unique_lck(cegn_mutex testmutex)
函数中定义了一个互斥量cegn_lock
std::unique_lockcegn_mutex cegn_lock(testmutex);
该互斥量在函数退出的时候生命周期就结束了所以自动销毁最终导致无法互斥那是在想要封装如何实现呢可以自己协议个类封装
完整的简单代码如下
#include iostream
#include thread
#include mutex
#include windows.hclass MutexWrapper {
public:MutexWrapper(std::mutex mutex) : m_mutex(mutex) {m_mutex.lock();}~MutexWrapper() {m_mutex.unlock();}private:std::mutex m_mutex;
};std::mutex g_mutex_test;
int g_dwVal 0;void FastWriteData(int i) {while (1) {MutexWrapper lock(g_mutex_test);g_dwVal;std::cout FastWriteData Set dwVal g_dwVal \n;Sleep(1000);}
}void SlowWriteData(int i) {while (1) {MutexWrapper lock(g_mutex_test);g_dwVal;std::cout SlowWriteData Set dwVal g_dwVal \n;Sleep(3000);}
}int main() {std::cout main start !! std::endl;std::thread thread1 std::thread(FastWriteData, 0);std::thread thread2 std::thread(SlowWriteData, 0);thread1.join();thread2.join();getchar();return 1;
}如此运行正常了 修改下例程让两个进程都整行跑
void FastWriteData(int i) {while (1) {{MutexWrapper lock(g_mutex_test);g_dwVal;std::cout FastWriteData Set dwVal g_dwVal \n;}Sleep(1000);}
}void SlowWriteData(int i) {while (1) {{MutexWrapper lock(g_mutex_test);g_dwVal;std::cout SlowWriteData Set dwVal g_dwVal \n;}Sleep(3000);}
}
如上代码就基本都正常了。
当然也可以将互斥锁修改为读写锁如下
class MutexWrapper {
public:MutexWrapper(std::shared_mutex mutex) : m_mutex(mutex) {m_mutex.lock();}~MutexWrapper() {m_mutex.unlock();}private:std::shared_mutex m_mutex;
};std::shared_mutex g_mutex_test;
代码也运行正常了。
综上
1基于RAIIC的很多变量生命周期有限必须特别注意智能变量的生命周期。
2如果需要封装读写锁不能简单函数分装实在不行就用一个类封装吧
3要熟练掌握std::threadstd::shared_mutexstd::mutex的用法这个是变法互斥基本要求