我正在实现我自己的日志系统以达到性能目的(因为我基本上只需要一个缓冲区)。我现在拥有的是这样的:
// category => messages
static std::unordered_map<std::string, std::ostringstream> log;
void main() {
while (true) {
log["info"] << "Whatever";
log["192.168.0.1"] << "This is a dynamic entry";
dump_logs();
}
}
void dump_logs() {
// i do something like this for each category, but they have different save strategies
if (log["info"].tellp() > 1000000) {
// save the ostringstream to a file
// clear the log
log["info"].str("")
}
}
完美无缺。但是,我刚刚添加了线程,我不确定这段代码是否是线程安全的。有什么提示吗?
答案 0 :(得分:1)
您可以通过声明地图 extern
来使此线程安全。如果您要在翻译单元中使用它,请将其设为static
并在一个 翻译单元中定义,否则{{ 1}}很好。
您仍需要同步将日志写入磁盘。 互斥锁应修复:
// category => messages (one per thread)
thread_local static std::unordered_map<std::string, std::ostringstream> log;
void main() {
while (true) {
log["info"] << "Whatever";
log["192.168.0.1"] << "This is a dynamic entry";
dump_logs();
}
}
void dump_logs() {
static std::mutex mtx; // mutex shared between threads
// i do something like this for each category, but they have different save strategies
if (log["info"].tellp() > 1000000) {
// now I need to care about threads
// use { to create a lock that will release at the end }
{
std::lock_guard<std::mutex> lock(mtx); // synchronized access
// save the ostringstream to a file
}
// clear the log
log["info"].str("");
}
}
答案 1 :(得分:1)
在POSIX系统上,如果您始终将数据写入文件末尾,则多线程将数据写入文件的最快方法是使用低级C风格的open()
追加模式,只需拨打write()
,因为POSIX standard for write()
状态:
在常规文件或其他能够搜索的文件上,实际写入 数据应从文件中指明的文件中的位置开始 与fildes相关的文件偏移量。在成功返回之前 write(),文件偏移量应增加字节数 实际写的。在常规文件中,如果是最后一个字节的位置 写入大于或等于文件的长度,长度 该文件应设置为此位置加一。
...
如果设置了文件状态标志的O_APPEND标志,则为文件偏移量 应在每次写入之前设置为文件的末尾,否则 干预文件修改操作应在更改之间进行 文件偏移和写操作。
因此,从进程内到以附加模式打开的文件的所有write()
调用都是原子的。
不需要互斥锁。
几乎。您唯一需要关注的问题是
如果
write()
在成功写入后被信号中断 一些数据,它应返回写入的字节数。
如果您对环境有足够的控制权,那么在写入部分数据后,您可以确保对write()
的调用不会被信号中断,这是写入数据的最快方法来自多个线程的文件 - 您正在使用操作系统提供的锁定文件描述符,以确保遵守POSIX指定的行为,并且只要您生成要写入的数据而没有任何锁定,该文件描述符锁定是整个数据路径中唯一的一个。无论您在代码中执行什么操作,该锁都将位于您的数据路径中。