Access to singleton object from another thread

2019-07-17 05:25发布

问题:

I call service method using

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

Service has object 'loggingService' with I was get using Spring.Net

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

'LoggingService' class is singleton. It writes log info to log.txt.

When I try to call loggingService.Info("test") in this service method, I get exception: file is busy by another process.

How can I access to the loggingService?

回答1:

Your singleton is apparently per-thread.
You will need some way of passing the LoggingService across threads.

For example, you could set service.loggingService in the original thread.

Alternatively, you might be able to configure Spring.Net to make it a non-thread-local singleton.

Note that your LoggingService must be thread-safe, or you'll get strange errors at runtime.



回答2:

I had a similar issue while writing some client side application that used a bunch of threads.

Basically you want your LoggingService to keep an internal queue (whose access should be controlled via a lock) and every time you call the log method you only append the message to this queue. At the end of the log method check if the queue is currently being written to a file and if not, start writing.



回答3:

public static class SingletonLoggingService
{
    public static ILoggingService LoggingService = ObjectBuilder.GetObjectByName("LoggingService"); 
}


SingletonLoggingService.LoggingService.Info("Test");


回答4:

I did it!

I use Queue and threading:

    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;
            }
        }
    }
}

I call Shutdown() at the end of app:

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


标签: c# threadpool