C ++ std :: list作为静态成员变量 - 并发问题?

时间:2011-03-10 04:57:59

标签: c++ multithreading static error-handling

我写了一个负责跟踪错误消息的类,它使用静态std :: list来跟踪消息。我从中继承了大多数其他类,使它们能够写入常见的错误日志。在程序关闭时,错误日志将写入文件。这是一个多线程的应用程序但是...我想到我可能会在这里问问题......

class ErrorLogger
{
public:  
  void writeErrorMessage( string message );
  // ... etc
private:
  std::list<string> _theErrorMessages;
  // ... etc
};

我一直从这里派出几个班级。表面的例子:

class MultiThreadingWidget : public ErrorLogger
{
public:
  void run()
  {
     // ...
     if( !isWorking ) 
     { writeErrorMessage( "MultiThreadingWidget::run failed()..."); };
     // ...
  }
};

坦率地说,我并不十分关注并发问题,因为它们会影响错误日志 - 在运行的多线程部分,如果有一个值得写入日志的错误,那几乎肯定是一个致命的错误 - 但我担心性能问题。

将ErrorLog变为Singleton模式会更好吗,还是出于所有实际目的而做同样的事情?

例外不是此项目的选项。

提前致谢!

3 个答案:

答案 0 :(得分:1)

  

我写了一个负责跟踪错误消息的类,它使用静态std :: list来跟踪消息。

它没有被声明为静态 - 这是什么?

编辑:看到这是一个错字,它应该被声明为静态。但是,响应结束时的建议可以帮助您在不引入线程错误的情况下获得最佳速度。

  

坦率地说,我并不十分关注并发问题,因为它们会影响错误日志 - 在运行的多线程部分,如果有一个值得写入日志的错误,那几乎肯定是一个致命的错误 - 但我担心性能问题。

您的担忧是倒退的 - 没有理由引入难以跟踪且容易避免的错误。

问:如果它几乎肯定是致命的,因此(希望)非常罕见,在常规执行期间锁定成本会是多少?

A:只有一些内存(用于锁定)。你不会经常写信。

问:在执行的这个阶段,为什么这个成本会很重要?

答:程序可能遇到了致命的事情

问:为什么正确编写的并行程序被认为太慢,甚至比典型硬件上的单线程实现更慢?

答:他们不是。只需为当前和未来的机器编写程序。好吧,有些情况下这不好,但我怀疑情况并非如此,因为你正在编写程序的其他部分以便并发执行。

如果性能在这里非常重要,那么你应该编写你的并发实现。

  

将ErrorLog变为Singleton模式会更好吗,还是出于所有实际目的而做同样的事情?

没有。创建多个包含自己消息的实例,如果您喜欢对消息进行分类的话。如果出现以下情况,多个实例将减少记录器类型的竞争 1)速度很重要 2)你真的有很多要记录的消息

使用多个记录器,如果您要编写大量消息并从多个线程推送消息,则调用者不会等待经常获取锁定。

终止时,收集所有记录器的所有消息并将其写入磁盘。这样,不同的记录器(具有不同的上下文)可以按类别(实例)或时间(如果您愿意)输出其消息。

如果你知道它是致命的,那么重新考虑立即写(如0xC0DEFACE建议的那样)。

答案 1 :(得分:0)

首先永远不要等待记录,尽快做到。如果您遇到崩溃或所有未记录的消息都消失了,那么请将它们放入该日志文件中!

其次是的,尝试从多个线程写入一个文件将是有问题的,并且有一个单独的实例,就像处理所有操作的单例一样是个好主意。只需确保对日志文件或消息队列的任何写入一次只完成一个线程,否则您将难以跟踪线程相关的崩溃/问题。

答案 2 :(得分:0)

您应该考虑切换到全局日志记录功能或类 - 从类继承只是为了获取对日志记录工具的访问权似乎很奇怪。这不会对线程产生影响,但它会使您的代码在以后不易出现维护问题。

据说:std::list不保证是线程安全的。您可以使用互斥锁(例如,使用pthreads或您正在使用的任何线程库)解决此问题,并在对错误日志进行任何写入之前将其锁定。如果您担心性能,可以执行以下两项操作之一:

  1. 消除非调试版本的日志记录。这样,当您不需要时,不会产生任何开销。请注意,如果从调试类继承,则实现这一点非常严格。

  2. 以其他方式消除锁定。您可以让每个线程都有自己独立的日志,以定期的间隔与主日志连接。