【问题标题】:Access to singleton object from another thread从另一个线程访问单例对象
【发布时间】:2009-12-22 14:19:23
【问题描述】:

我调用服务方法使用

ThreadPool.QueueUserWorkItem(o => service.Method(arg1, arg2));

Service 具有对象“loggingService”,而我是使用 Spring.Net 获得的

private readonly ILoggingService loggingService = ObjectBuilder.GetObjectByName("LoggingService");

'LoggingService' 类是单例的。它将日志信息写入 log.txt。

当我尝试在此服务方法中调用 loggingService.Info("test") 时,出现异常:文件正被另一个进程占用。

如何访问 loggingService?

【问题讨论】:

  • 你问的是什么编程语言?
  • 哦。对不起。我使用 C#(WPF 应用程序)

标签: c# threadpool


【解决方案1】:

你的单例显然是每个线程的。
您将需要某种方式跨线程传递LoggingService

例如,您可以在原始线程中设置service.loggingService

或者,您可以配置 Spring.Net 以使其成为非线程本地单例。

请注意,您的 LoggingService 必须是线程安全的,否则在运行时会出现奇怪的错误。

【讨论】:

    【解决方案2】:

    我在编写一些使用一堆线程的客户端应用程序时遇到了类似的问题。

    基本上,您希望您的 LoggingService 保留一个内部队列(其访问权限应通过锁来控制),并且每次调用 log 方法时,您只需将消息附加到此队列。在 log 方法结束时检查队列当前是否正在写入文件,如果没有,则开始写入。

    【讨论】:

      【解决方案3】:
      public static class SingletonLoggingService
      {
          public static ILoggingService LoggingService = ObjectBuilder.GetObjectByName("LoggingService"); 
      }
      
      
      SingletonLoggingService.LoggingService.Info("Test");
      

      【讨论】:

        【解决方案4】:

        我做到了!

        我使用队列和线程:

            internal class LoggingService : ILoggingService {
            private readonly Queue<LogEntry> queue = new Queue<LogEntry>();
            private Thread waiter;
        
            public LoggingService() {
                waiter = new Thread(AddLogEntry);
                waiter.Start();
            }
        
            public void Shutdown() {
                try {
                    waiter.Abort();
                } catch {}
            }
        
            public void Error(string s, Exception e) {
                lock (queue) {
                    queue.Enqueue(new LogEntry(s, e, LogEntryType.Error));
                }
            }
        
            public void Warning(string message) {
                lock (queue) {
                    queue.Enqueue(new LogEntry(message, LogEntryType.Warning));
                }
            }
        
            public void Info(string message) {
                lock (queue) {
                    queue.Enqueue(new LogEntry(message, LogEntryType.Info));
                }
            }
        
            private void AddLogEntry(object state) {
                while (true) {
                    lock (queue) {
                        if (queue.Count > 0) {
                            LogEntry logEntry = queue.Dequeue();
                            switch (logEntry.Type)
                            {
                                case LogEntryType.Error:
                                     logWriter.Error(logEntry.Message, logEntry.Exception);
                                    break;
                                case LogEntryType.Warning:
                                    logWriter.Warning(logEntry.Message);
                                    break;
                                case LogEntryType.Info:
                                    logWriter.Info(logEntry.Message);
                                    break;
                            }
                        }
                    }
                    Thread.Sleep(100);
                    if (waiter.ThreadState == ThreadState.Aborted) {
                        waiter = null;
                        break;
                    }
                }
            }
        }
        

        我在应用程序结束时调用 Shutdown():

                protected override void OnExit(ExitEventArgs e) {
                loggingService.Shutdown();
                base.OnExit(e);
            }
        

        【讨论】:

          猜你喜欢
          • 2014-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多