在上一节的代码中加入了向文本文件中写入日志的代码:

UINT CMFCApplication1Dlg::Thread1(LPVOID pParam)
{
try{
size_t q_size = ; //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 = ; i < ; i++){
Sleep();
console->info("Thread 1,Count {}",i);
Sleep();
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 ;
}
UINT CMFCApplication1Dlg::Thread2(LPVOID pParam)
{
try{
size_t q_size = ; //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 = ; i < ; i++){
Sleep();
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 ;
}

实验表明,两个线程同时运行,由于写入一个的是同一个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 = ; i < ; i++){
Sleep();
DWORD dReturn = WaitForSingleObject(hEvent2, INFINITE);
if (WAIT_OBJECT_0 == dReturn)
{
console->info(" Event2 signaled ! ");
ResetEvent(hEvent2);
Sleep();
}
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();
}
}
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 ;
}
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 = ; i < ; i++){
Sleep();
DWORD dReturn = WaitForSingleObject(hEvent1, INFINITE);
if (WAIT_OBJECT_0 == dReturn)
{
console->info(" Event1 signaled ! ");
ResetEvent(hEvent1);
Sleep();
}
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 ;
}

原理就是:先启动Event2,这样Thread1就可以执行,执行完第一个循环后把Event1置为有信号,Event2为无信号。这样处于等待状态的Thread2就可以执行了,Thread2执行第一个循环之后把Event2置位有信号,Event1置为无信号。

最后发现Thread1和Thread2交替执行!!!!这样子没什么意义吧。。。

放在cpp文件的开头定义为全局变量,输出在类的成员函数中执行,编译没问题,但运行时无输出。为何?

c++ 日志输出库 spdlog 简介(4)- 多线程txt输出日志的更多相关文章

  1. c++ 日志输出库 spdlog 简介(1)

    参考文章: log库spdlog简介及使用 - 网络资源是无限的 - CSDN博客 http://blog.csdn.net/fengbingchun/article/details/78347105 ...

  2. c++日志输出库 spdlog 简介(3)多线程控制台输出日志

    spdlog源码分析:https://www.cnblogs.com/eskylin/p/6483199.html spdlog的异步模式使得spdLog可以支持多线程,于是写了一个多线程的小例子: ...

  3. c++ 日志输出库 spdlog 简介(2)

    继续上一篇,example.cpp解析. 1.set_pattern 自定义日志格式 官方参考:https://github.com/gabime/spdlog/wiki/3.-Custom-form ...

  4. 细说Java主流日志工具库

    概述 在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息. 在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子. 我们先来逐一了解一下主流日志工具. java.util ...

  5. 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)

    前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...

  6. zlog 纯C日志函数库的简单使用方法

    zlog简述: log是一个高性能.线程安全.灵活.概念清晰的纯C日志函数库. 事实上,在C的世界里面没有特别好的日志函数库(就像JAVA里面的的log4j,或者C++的log4cxx).C程序员都喜 ...

  7. Java主流日志工具库

    在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息.在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子.我们先来逐一了解一下主流日志工具. 1.java.util.lo ...

  8. Log4j配置的经典总结,打印日志文件,日志存库

        一.介绍 Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制 日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务 器.NT的事件记录器.UNIX Sy ...

  9. 如何提升mysql replication的性能&amp;多线程传输二进制日志

    1,最好使用内网或者专线链路传输binlog数据 (千兆网卡.还不够的话,bounding 技术,扩展带宽) 在my.cnf中强制使用内网ip传输数据bind-address=ip2,将二进制保存在独 ...

随机推荐

  1. Ajax的get方式传值 避免& 与= 号

    js代码 例如: var name = $("#name”).value;//为a&b=7 name=encodeURLComponent(name); 可以将a&b=7转化 ...

  2. getchar()、putchar()、gets()、puts()、cin.get()、cin.getline()、getline()

    1.getchar: 原型为int getchar(void). 它从stdin里读取一个字符.返回值为用户输入的ASCⅡ码,出错返回-1. eg:c=getchar(). 2.putchar: 原型 ...

  3. LibreOJ 6277 数列分块入门 1(分块)

    题解:感谢hzwer学长和loj让本蒟蒻能够找到如此合适的入门题做. 这是一道非常标准的分块模板题,本来用打标记的线段树不知道要写多少行,但是分块只有这么几行,极其高妙. 代码如下: #include ...

  4. discrete

    discrete - 必应词典 美[dɪ'skrit]英[dɪ'skriːt] adj.离散的:分离的:各别的 网络不连续的:分立的:离散型

  5. PHP的zip、unzip类详解

    1.打开一个ZIP包,用于读取.写入或修改 open(string $filename [, int $flags]) $filename - 文件名 $flags - 打开模式 ZIPARCHIVE ...

  6. VMware安装centos虚拟机 通过NAT与主机互通并能上网

    1.关于centos虚拟机的安装,我这里就不详细说明了,网上有很多教程,默认你们已经安装好.       (我的环境是centos6.6 x86 最小安装版) 2.右键虚拟主机,选择设置选项. 3.在 ...

  7. Java 的CardPanel用法

    Java code? 1 2 3 4 5 6               card = new CardLayout(5,5);//5,5是组件间隔                pane = new ...

  8. 768A Oath of the Night's Watch

    A. Oath of the Night's Watch time limit per test 2 seconds memory limit per test 256 megabytes input ...

  9. Python和JavaScript间代码转换4个工具-乾颐堂

    Python 还是 JavaScript?虽然不少朋友还在争论二者目前谁更强势.谁又拥有着更为光明的发展前景,但毫无疑问,二者的竞争在 Web 前端领域已经拥有明确的答案.立足于浏览器平台,如果放弃 ...

  10. laravel数据库操作

    一.配置文件路径:/.env DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT= DB_DATABASE=test DB_USERNAME=root DB_P ...