多线程学习记录2

使用多个锁导致的死锁问题

code 7:

#include 
#include 
#include 
#include 
#include 
//std::mutex mu;
class LogFile{
public:
	LogFile(){
		//f.open("log.txt");
	}
	void log1(std::string s, int i){
		std::lock_guard lg1(m_mutex1);
		std::lock_guard lg2(m_mutex2);
		std::cout<< " count i:" << i << std::endl;
	}
	void log2(std::string s, int i){
		std::lock_guard lg2(m_mutex2);
		std::lock_guard lg1(m_mutex1);
		std::cout << " count i:" << i << std::endl;
	}
protected:
private:
	std::mutex m_mutex1;
	std::mutex m_mutex2;
};
void test_funtion(LogFile& lf){
	for (int i = 0; i < 100; ++i)
	{
		lf.log1("test_funtion ", i);
	}
}
int main()
{
	LogFile logFile;
	std::thread t1(test_funtion,std::ref(logFile));
	for (int i = 0; i < 100; ++i)
	{
		logFile.log2("main ", i);
	}
	t1.join();
	return 0;
}
代码中log1和log2没有实际功能,只是为了测试,当需要多个锁时,若上锁的顺序不同,可能会发生死锁现象。t1线程执行到log1,锁住m_mutex1,马上要执行

		std::lock_guard lg2(m_mutex2);
主线程执行到log2,锁住m_mutex2,马上要执行

std::lock_guard lg1(m_mutex,1);

这样t1会等待m_mutex2释放,而主线程会等待m_mutex1释放,这样就死锁了。所以要保证mutex上锁的顺序要一致,使用这种办法可以不用操心上锁顺序

	void log1(std::string s, int i){
		std::lock(m_mutex1, m_mutex2);
		std::lock_guard lg1(m_mutex1,std::adopt_lock);
		std::lock_guard lg2(m_mutex2, std::adopt_lock);
		std::cout<< " count i:" << i << std::endl;
	}
	void log2(std::string s, int i){
		std::lock(m_mutex1, m_mutex2);
		std::lock_guard lg2(m_mutex2, std::adopt_lock);
		std::lock_guard lg1(m_mutex1, std::adopt_lock);
		std::cout << " count i:" << i << std::endl;
	}

code8:

#include 
#include 
#include 
#include 
#include 
class LogFile{
public:
	LogFile(){
		//f.open("log.txt");
	}
	void log1(std::string s, int i){
		std::lock_guard lg1(m_mutex1);
		std::cout<< " count i:" << i << std::endl;
	}
protected:
private:
	std::mutex m_mutex1;
	//std::fstream f;
};
void test_funtion(LogFile& lf){
	for (int i = 0; i < 100; ++i)
	{
		lf.log1("test_funtion ", i);
	}
}
int main()
{
	LogFile logFile;
	std::thread t1(test_funtion,std::ref(logFile));
	for (int i = 0; i < 100; ++i)
	{
		logFile.log1("main ", i);
	}
	t1.join();
	return 0;
}
可以使用unique_lock代替lock_guard,unique_lock使用更为灵活。

	void log1(std::string s, int i){
		std::unique_lock lg1(m_mutex1);
		std::cout<< " count i:" << i << std::endl;
		lg1.unlock();//可灵活上锁解锁
		lg1.lock();
		lg1.unlock();
	}
	void log1(std::string s, int i){
		std::unique_lock lg1(m_mutex1,std::defer_lock);//未上锁
		lg1.lock();
		std::cout<< " count i:" << i << std::endl;
		lg1.unlock();
		lg1.lock();
		lg1.unlock();
	}
code9:

#include 
#include 
#include 
#include 
#include 
std::mutex mu;
class LogFile{
public:
	LogFile(){
		f.open("log.txt");
	}
	void log(std::string s, int i){
		std::lock_guard lg(m_mutex);
		f << s << " count i:" << i << std::endl;
	}
protected:
private:
	std::mutex m_mutex;//保护f
	std::ofstream f;
};
void test_funtion(LogFile& lf){
	for (int i = 0; i < 100; ++i)
	{
		lf.log("test_funtion ", i);
	}
}
int main()
{
	LogFile logFile;
	std::thread t1(test_funtion, std::ref(logFile));
	for (int i = 0; i < 100; ++i)
	{
		logFile.log("main ", i);
	}
	t1.join();
	return 0;
}
LogFile在构造函数打开txt文件,这个没有必要,什么时候用什么时候打开就好。可以改成:

class LogFile{
public:
	LogFile(){
	}
	void log(std::string s, int i){
		
		if (!f.is_open())
		{
			std::lock_guard lg(m_mutex_open);
			f.open("log.txt");
		}
		std::lock_guard lg(m_mutex);
		f << s << " count i:" << i << std::endl;
	}
protected:
private:
	std::mutex m_mutex;//打印使用
	std::mutex m_mutex_open;//打开文件使用
	std::ofstream f;
};
这样也不是线程安全的,如果多个线程都执行至

std::lock_guard lg(m_mutex_open);
一个线程释放m_mutex_open后,另一个线程会再次打开f,会导致f被打开两次。所以is_open应该和open同步,这样

	void log(std::string s, int i){
		{
			if (!f.is_open())
			{
				std::lock_guard lg(m_mutex_open);
				f.open("log.txt");
			}
		}
	
		std::lock_guard lg(m_mutex);
		f << s << " count i:" << i << std::endl;
	}
频繁上锁解锁会影响性能,c++11提供了更好的办法 Lazy Initialization
class LogFile{
public:
	LogFile(){
	}
	void log(std::string s, int i){
		std::call_once(m_flag_open, [&](){f.open("log.txt"); });
		std::lock_guard lg(m_mutex);
		f << s << " count i:" << i << std::endl;
	}
protected:
private:
	std::mutex m_mutex;//打印使用
	std::once_flag m_flag_open;
	//std::mutex m_mutex_open;//打开文件使用
	std::ofstream f;
};









你可能感兴趣的:(c++多线程入门)