在上一節的代碼中加入了向文本文件中寫入日志的代碼:
UINT CMFCApplication1Dlg::Thread1(LPVOID pParam) { try{ size_t q_size = 4096; //queue size must be power of 2 spdlog::set_async_mode(q_size, spdlog::async_overflow_policy::block_retry); auto console = spd::stdout_color_st("console1"); for (int i = 0; i < 10; i++){ Sleep(500); console->info("Thread 1,Count {}",i); Sleep(10); auto daily = spd::basic_logger_mt("basic1", "logs/basic-log.txt"); daily->info("Thread 1,Count {}", i); spdlog::drop("basic1"); } } catch (const spd::spdlog_ex& ex) { std::cout << "Thread 1 Logger failed: " << ex.what() << std::endl; } spdlog::drop("console1"); return 0; } UINT CMFCApplication1Dlg::Thread2(LPVOID pParam) { try{ size_t q_size = 4096; //queue size must be power of 2 spdlog::set_async_mode(q_size, spdlog::async_overflow_policy::block_retry); auto console = spd::stdout_color_st("console2"); //auto daily2 = spd::basic_logger_mt("basic2", "logs/basic-log.txt"); for (int i = 0; i < 10; i++){ Sleep(500); console->info("Thread 2,Count {}", i); auto daily = spd::basic_logger_mt("basic2", "logs/basic-log.txt"); daily->info("Thread 2,Count {}", i); spdlog::drop("basic2"); } } catch (const spd::spdlog_ex& ex) { std::cout << "Thread 2 Logger failed: " << ex.what() << std::endl; } spdlog::drop("console2"); return 0; }
實驗表明,兩個線程同時運行,由於寫入一個的是同一個txt文件basic-log.txt,運行時會發生異常,如下圖第二行的 Permission denied。
由於線程1打開了basic-log.txt文件,在其關閉文件也就是drop之前如果線程2也去打開這個文件,就會發生沖突。
如何解決呢?
(1)ex.what()返回const char * 類型,也就是字符串指針,可以在catch中判斷異常類型,如果是Permission denied這種類型的異常,可以重新申請輸出日志。
(2)或者用一個線程鎖,防止兩個線程同時訪問一個文件。
首先定義兩個全局變量:
HANDLE hEvent1 = NULL;
HANDLE hEvent2 = NULL;
然后在按鈕函數中初始化兩個Event:
void CMFCApplication1Dlg::OnBnClickedButton1() { hEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL);//手動復位,初始為無信號 hEvent2 = CreateEvent(NULL, TRUE, TRUE, NULL);//手動復位,初始為有信號 AfxBeginThread(Thread1, this); AfxBeginThread(Thread2, this); }
在線程函數中設定互鎖機制:
UINT CMFCApplication1Dlg::Thread1(LPVOID pParam) { try{ //size_t q_size = 4096; //queue size must be power of 2 //spdlog::set_async_mode(q_size, spdlog::async_overflow_policy::block_retry); auto console = spd::stdout_color_st("console1"); for (int i = 0; i < 10; i++){ Sleep(900); DWORD dReturn = WaitForSingleObject(hEvent2, INFINITE); if (WAIT_OBJECT_0 == dReturn) { console->info(" Event2 signaled ! "); ResetEvent(hEvent2); Sleep(20); } console->info("Thread 1,Count {}",i); auto daily = spd::basic_logger_mt("basic1", "logs/basic-log.txt"); daily->info("Thread 1,Count {}", i); spdlog::drop("basic1"); SetEvent(hEvent1); Sleep(20); } } catch (const spd::spdlog_ex& ex) { std::cout << "Thread 1 Logger failed: " << ex.what() << std::endl; const char * ExceptionTpye = ex.what(); std::cout<<strlen(ExceptionTpye)<<endl; } spdlog::drop("console1"); return 0; } UINT CMFCApplication1Dlg::Thread2(LPVOID pParam) { try{ //size_t q_size = 4096; //queue size must be power of 2 //spdlog::set_async_mode(q_size, spdlog::async_overflow_policy::block_retry); auto console = spd::stdout_color_st("console2"); for (int i = 0; i < 10; i++){ Sleep(500); DWORD dReturn = WaitForSingleObject(hEvent1, INFINITE); if (WAIT_OBJECT_0 == dReturn) { console->info(" Event1 signaled ! "); ResetEvent(hEvent1); Sleep(20); } console->info("Thread 2,Count {}", i); auto daily = spd::basic_logger_mt("basic2", "logs/basic-log.txt"); daily->info("Thread 2,Count {}", i); spdlog::drop("basic2"); SetEvent(hEvent2); } } catch (const spd::spdlog_ex& ex) { std::cout << "Thread 2 Logger failed: " << ex.what() << std::endl; } spdlog::drop("console2"); return 0; }
原理就是:先啟動Event2,這樣Thread1就可以執行,執行完第一個循環后把Event1置為有信號,Event2為無信號。這樣處於等待狀態的Thread2就可以執行了,Thread2執行第一個循環之后把Event2置位有信號,Event1置為無信號。
最后發現Thread1和Thread2交替執行!!!!這樣子沒什么意義吧。。。
放在cpp文件的開頭定義為全局變量,輸出在類的成員函數中執行,編譯沒問題,但運行時無輸出。為何?

