C++ 宏定义打印日志

初始实现:

#define LOG_INFO(...) {\

fprintf(stderr, "%s :Line %d :\t", __FILE__, __LINE__);\

fprintf(stderr, __VA_ARGS__);\

fprintf(stderr, "\n");\

}

...

进一步用宏控制是否打印测试日志,修改方案:

#define TEST_ON 1

if (TEST_ON== 1) { \

#ifndef TEST_ON

#define TEST_ON 1

#endif

#define TEST_LOG(...) {\

    if (TEST_ON== 1) { \

        ALOGE(__VA_ARGS__);\

    } \

    else \

    { \

        ; \

    } \

}

开线程打印拓展,例如以下耗时场景:

#define TEST_ON

#define TEST_LOG(...) {\
#ifdef TEST_ON\
std::this_thread::sleep_for(std::chrono::milliseconds(100)); \
LOG_INFO("Mytest", __VA_ARGS__); \
#endif \
}

在宏定义中直接使用 `std::this_thread::sleep_for` 是不好的做法,这会让整个线程暂停执行。

改成使用定时器或线程睡眠方式来控制延迟。

可以改成以下代码:

```c++
#include <thread>
#include <chrono>

...

#define TEST_ON
#define TEST_LOG(...) {\
    if (TEST_ON) { \
        std::thread([](auto&&... args) { \
            std::this_thread::sleep_for(std::chrono::milliseconds(100)); \
            LOG_INFO("MyTest", std::forward<decltype(args)>(args)...); \
        }, __VA_ARGS__).detach(); \
    } \
}
#endif
```

这里使用了 `std::thread` 创建了一个新线程来进行延迟,并使用 `detach` 分离该线程,让其自行运行于后台,这样可以不阻塞当前线程。

注意:需要在使用 `__VA_ARGS__` 时加上宏定义中的 `std::forward<decltype(args)>(args)...` 语句,将可变参数转发给函数模板(`CAMX_LOG_INFO`)进行参数推导。

使用线程来延迟日志输出的做法可以避免当前线程暂停,但也会带来线程频繁创建与销毁的问题。这样的开销可能会对性能产生负面影响。

为了解决这个问题,可以考虑使用线程池来重用线程,减少创建和销毁线程的开销。线程池可以通过预先创建一定数量的线程,并维护一个任务队列来实现。当需要执行任务时,先将任务加入队列,然后由线程池内的线程来执行。

因此,可以将线程池的实现封装成一个类,然后在宏定义中使用该类来控制日志输出。这样可以避免线程创建与销毁的开销。

以下是使用线程池来实现的例子:

```c++
#include <thread>
#include <chrono>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <functional>

class ThreadPool {
public:
    explicit ThreadPool(size_t size) {
        for (size_t i = 0; i < size; ++i) {
            threads_.emplace_back([this] {
                while (true) {
                    std::unique_lock<std::mutex> lock(mutex_);
                    cond_.wait(lock, [this]{ return !tasks_.empty() || stop_; });
                    if (stop_ && tasks_.empty()) {
                        return;
                    }
                    auto task = std::move(tasks_.front());
                    tasks_.pop();
                    lock.unlock();
                    task();
                }
            });
        }
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(mutex_);
            stop_ = true;
        }
        cond_.notify_all();
        for (auto& thread : threads_) {
            thread.join();
        }
    }

    template<class F>
    void addTask(F&& task) {
        {
            std::unique_lock<std::mutex> lock(mutex_);
            tasks_.emplace(std::forward<F>(task));
        }
        cond_.notify_one();
    }

private:
    std::vector<std::thread> threads_;
    std::queue<std::function<void()>> tasks_;
    std::mutex mutex_;
    std::condition_variable cond_;
    bool stop_ = false;
};

static ThreadPool threadPool{4};

...

#define TEST_ON
#define TEST_LOG(...) {\
    if (TEST_ON) { \
        threadPool.addTask([=]{ \
            std::this_thread::sleep_for(std::chrono::milliseconds(100)); \
            LOG_INFO("MyTest", __VA_ARGS__); \
        }); \
    } \
}
```

这里使用了 `ThreadPool` 类来实现线程池的功能。该类在构造时会创建 `size` 个线程,并在析构时释放所有线程。该类提供了 `addTask` 方法以添加任务队列,并使用条件变量 `cond_` 唤醒空闲线程来执行任务。在宏定义中,使用线程池的 `ThreadPoo::addTask` 方法来将任务加入任务队列中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值