多线程学习记录2

来源:互联网 发布:ubuntu输入法设置中文 编辑:程序博客网 时间:2024/06/05 06:20

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

code 7:

#include <iostream>#include <thread>#include <mutex>#include <string>#include <fstream>//std::mutex mu;class LogFile{public:LogFile(){//f.open("log.txt");}void log1(std::string s, int i){std::lock_guard<std::mutex> lg1(m_mutex1);std::lock_guard<std::mutex> lg2(m_mutex2);std::cout<< " count i:" << i << std::endl;}void log2(std::string s, int i){std::lock_guard<std::mutex> lg2(m_mutex2);std::lock_guard<std::mutex> 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<std::mutex> lg2(m_mutex2);
主线程执行到log2,锁住m_mutex2,马上要执行

std::lock_guard<std::mutex> 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<std::mutex> lg1(m_mutex1,std::adopt_lock);std::lock_guard<std::mutex> 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<std::mutex> lg2(m_mutex2, std::adopt_lock);std::lock_guard<std::mutex> lg1(m_mutex1, std::adopt_lock);std::cout << " count i:" << i << std::endl;}

code8:

#include <iostream>#include <thread>#include <mutex>#include <string>#include <fstream>class LogFile{public:LogFile(){//f.open("log.txt");}void log1(std::string s, int i){std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lg1(m_mutex1,std::defer_lock);//未上锁lg1.lock();std::cout<< " count i:" << i << std::endl;lg1.unlock();lg1.lock();lg1.unlock();}
code9:

#include <iostream>#include <thread>#include <mutex>#include <string>#include <fstream>std::mutex mu;class LogFile{public:LogFile(){f.open("log.txt");}void log(std::string s, int i){std::lock_guard<std::mutex> lg(m_mutex);f << s << " count i:" << i << std::endl;}protected:private:std::mutex m_mutex;//保护fstd::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<std::mutex> lg(m_mutex_open);f.open("log.txt");}std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lg(m_mutex_open);f.open("log.txt");}}std::lock_guard<std::mutex> 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<std::mutex> 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;};









原创粉丝点击