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

发布于 2024-10-21 11:21:19 字数 741 浏览 2 评论 0原文

我编写了一个负责跟踪错误消息的类,它使用静态 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 成为单例模式会更好吗?还是说对于所有实际目的来说都是一样的?

该项目不可以选择例外。

提前致谢!

I wrote a class in charge of keeping track of error messages, which uses a static std::list to keep track of the messages. I subclass most other classes from this, to give them the ability to write to a common error log. At program close the error log is written to a file. This is a multithreaded application however ... it occurred to me I might be asking for problems here ...

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

I've been deriving several classes from this. Superficial example:

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

To be frank, I'm not terribly concerned about concurrency issues as they affect the error log -- during the multithreaded part of the run, if there's an error worthy of being written to the log, it's almost certainly a fatal error -- but I am concerned about performance issues.

Would it be better making the ErrorLog a Singleton pattern, or is that for all practical purposes the same thing?

Exceptions are not an option for this project.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

べ繥欢鉨o。 2024-10-28 11:21:19

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

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

编辑:看到这是一个拼写错误,它应该被声明为静态。但是,响应末尾的建议可能会帮助您获得最佳速度,而不会引入线程错误。

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

你的担忧是倒退的——没有理由引入一个难以跟踪且可以轻松避免的错误。

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

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

问:为什么在执行的现阶段该成本会很大?

答:程序可能遇到了致命的问题

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

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

如果性能在这里确实很重要,那么您应该编写并发实现。

将 ErrorLog 设置为单例模式会更好吗?还是说出于所有实际目的,这都是一样的?

不。创建多个实例来保存自己的消息(如果您喜欢这样对消息进行分类)。如果出现以下情况,多个实例将减少对记录器类型的竞争:
1)速度很重要
2)你确实有很多消息要

使用多个记录器来记录,如果你有很多消息要写入并且消息是从多个线程推送的,那么你的调用者不会经常等待获取锁。

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

如果您知道这是致命的,请重新考虑立即写入(如 0xC0DEFACE 所建议的那样)。

I wrote a class in charge of keeping track of error messages, which uses a static std::list to keep track of the messages.

it's not declared as static -- which is it?

EDIT: saw that was a typo, and that it should have been declared static. however, the suggestion at the end of the response may help you attain the best speed without introducing threading errors.

To be frank, I'm not terribly concerned about concurrency issues as they affect the error log -- during the multithreaded part of the run, if there's an error worthy of being written to the log, it's almost certainly a fatal error -- but I am concerned about performance issues.

your concerns are backwards -- there's no reason to introduce a bug which is difficult to track and can be easily avoided.

Q: if it's almost certainly fatal and thus (hopefully) quite rare, what will a lock cost during regular execution?

A: only some memory (for the lock). you will not write to it often.

Q: why would that cost be significant at this stage in execution?

A: the program has probably encountered something fatal

Q: why is a properly written parallel program considered to be too slow, or even slower than a single threaded implementation on typical hardware?

A: they're not. just write your program for current and future machines. ok, there are some cases where this is not good, but i suspect that is not the case since you're writing other parts of the program for concurrent execution.

you should write your implementation for concurrency, if performance really is important here.

Would it be better making the ErrorLog a Singleton pattern, or is that for all practical purposes the same thing?

no. create multiple instances which hold their own messages, if that's how you prefer to classify messages. multiple instances will reduce contest for the logger types if:
1) speed is important
2) you really have a lot of messages to log

using multiple loggers, your caller won't wait to acquire a lock as often, if you have a lot of messages to write and the messages are pushed from multiple threads.

at termination, gather all the messages from all loggers and write them to disk. this way the different loggers (with different contexts) can output their messages by category (instance), or time (if you prefer).

if you know it's fatal, then reconsider an immediate write (as 0xC0DEFACE suggests).

红颜悴 2024-10-28 11:21:19

首先,不要等待记录,尽快进行。如果您遇到崩溃或其他问题,所有未记录的消息都会消失,因此请将它们放入该日志文件中!

其次,是的,尝试从多个线程写入一个文件将会出现问题,并且拥有一个单独的实例(例如单例)来处理所有操作是一个好主意。只需确保对日志文件或消息队列的任何写入一次仅在一个线程上完成,否则您将很难追踪与线程相关的崩溃/问题。

First never wait to log, do it ASAP. If you get a crash or something all unlogged messages are gone, so get them into that log file!

Secondly yes, trying to write to the one file from multiple threads will be problematic and having a lone instance, like a singleton to handle all the operations is a good idea. Just make sure that any writing to the log file or to the message queue are only done one thread at a time, or you WILL get difficult to track down thread related crashes/issues.

夜还是长夜 2024-10-28 11:21:19

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

话虽如此:std::list 不能保证是线程安全的。您可以通过使用互斥锁(例如,使用 pthreads 或您已经使用的任何线程库)来解决此问题,并在写入错误日志之前锁定它。如果您担心性能,可以执行以下两种操作之一:

  1. 消除非调试构建的日志记录。这样,当您不需要时,就不会产生任何开销。请注意,如果您从调试类继承,则实现起来比严格需要的要困难。

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

You should consider switching to a global logging function or class -- it seems odd to inherit from a class just to gain access to a logging facility. This won't make a difference for threading, but it'll make your code less prone to maintenance issues later on.

With that said: std::list is not guaranteed to be thread-safe. You can resolve this by using a mutex (e.g., using pthreads or whatever threading library you are already using), and locking it before any writes to the error log. If you're worried about performance, you can do one of two things:

  1. Eliminate logging for non-debug builds. This way, you don't incur any overhead when you don't want it. Note that this is harder-than-strictly-necessary to implement if you inherit from your debugging class.

  2. Eliminate locking some other way. You could let each thread have its own separate log, to be joined with the main log at periodic intervals.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文