I've been struggling with an issue that recently popped up with a simple logtofile class I wrote.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Assets.Code
{
class TimingLogger
{
public static readonly TimingLogger Logger = new TimingLogger();
private static readonly string path = "C:\\Logs\\TimingLog.txt";
private readonly Mutex mutex = new Mutex(false, path);
private StreamWriter writer;
private readonly Queue<string> queue = new Queue<string>();
private bool isRunning;
private readonly object obj = new object();
private TimingLogger()
{
}
public void CheckPath()
{
if (!File.Exists(path))
{
File.Create(path);
}
}
public void Run()
{
isRunning = true;
while (isRunning)
{
lock (obj)
{
while (queue.Count <= 0)
{
Monitor.Wait(obj);
}
Log(queue.Dequeue());
}
}
}
public void Log(string line)
{
try
{
mutex.WaitOne();
writer = File.AppendText(path);
writer.WriteLine(line);
writer.Close();
}
catch (Exception)
{
//throw;
}
finally
{
mutex.ReleaseMutex();
}
}
public void Enqueue(string line)
{
lock (obj)
{
queue.Enqueue(line);
Monitor.Pulse(obj);
}
}
public void Stop()
{
isRunning = false;
}
}
}
This class was working just fine until recently, when I noticed that my log file wasn't showing the data I expected. Strangely enough, I hadn't changed any functionality of the class. Comparing an old, working version with my new one, the only difference was that some of my fields were made private and readonly. Besides that, the string path was changed to const. And to my complete bewilderment, changing this back to readonly fixed the issue I was having.
So my question is: How on earth is this possible? As far as I'm aware, there shouldn't functionally be any difference between readonly and const in this situation.
When debugging, the change in behavior is substantial, especially in the Run() method. What should happen here is that once Log(queue.Dequeue()); has been called, the thread will leave the lock statement and iterate through the while (isRunning) loop again. This seems pretty obvious, right? However, when I change the string path to const and debug again, the Log(queue.Dequeue()); is passed once and a single statement can be found in the log file, after which it simply doesn't do anything else ever again. It doesn't come past while (isRunning) again and it doesn't seem to leave the lock (obj) block. The logger thread seems to simply shutdown or pause after successfully calling Log(queue.Dequeue()); once.
Actually throwing the exception in the Log method makes no difference, no exceptions are thrown because the logging itself works fine.
I should mention that I'm using this code with Unity3D 5, which uses Mono. But still, this drastic change in behavior by such a small edit seems impossible to me. Can anyone explain why this is happening?
Thanks!
Here is the difference:
Consts are created in the metadata of the files, so when you run you class the value is already there.
ReadOnly are initialized in compile time, in your case, heres the trick, even though you declared path first then the mutex, the compiler initialized the mutex object first, here is why:
Your first static object to be initialized is the Logger:
public static readonly TimingLogger Logger = new TimingLogger();
Because you called the constructor, the non static members are initialized, making mutex the next member to be initialized. At this point you didnt initialized path yet, so
you are creating your mutex object with parameters false and null.
If you want to have the same error that you have with const using readonly, you can force the order of your static parameters initialization using a static constructor like :
static TimingLogger()
{
path = "C:\\Logs\\TimingLog.txt";
Logger = new TimingLogger();
}
Or simply putting path before Logger.
If you don't want to have the error using const, just change the mutex initialization using null parameter:
private readonly Mutex mutex = new Mutex(false, null);
Related
In c#, the main class created a Logger object that will be accessed by many threads. The logger object looks like (simplified)
public sealed class Logger
{
private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public Logger()
{
// create other objects here AND a thread that extracts
// from the queue and writes to a file
// because queue is thread safe this is perfectly ok
}
public void Log(string whatToLog)
{
// Now, is this safe? This method will be called by several threads
// perhaps at the same time
string s = whatToLog + " " + DateTime.Now.ToString();
queue.Enqueue(s);
// The thread created in the constructor will extract and log
}
}
Is this OK from a design point of view? My two questions are:
Is "string s = whatToLog + " " + DateTime.Now.ToString();" ok if this method is accessed by several threads at the same time? I guess yes because any thread will have its own copy of s, right?
If the Logger object is accessed by several threads at the same time using only the Log() method, is everything safe then?
Thanks
The class is pretty thread safe.
Some suggested improvements.
The class doesn't prevent multiple instances from being instantiated, which is important if you want to have all threads log to the same object. Perhaps the singleton pattern could be applied. Quick example of a pseudo singleton using a static constructor. Please note the default constructor is private preventing any other class from creating a logger.
A performance related change is to avoid concatenating strings when logging. Creating new string is not a cheap operation. Also, once DateTime.Now is converted to a string, it is much harder to evaluate. E.g. sorting messages by creation date and time, etc. In the following, whatToLog is paired up with DateTime.Now in a Tuple.
public sealed class Logger
{
public static Logger instance {get; private set;}
static Logger()
{
instance = new Logger();
}
private ConcurrentQueue<Tuple<string, DateTime>> queue = new ConcurrentQueue<Tuple<string, DateTime>>();
private Logger() {}
public void Log(string whatToLog)
{
queue.Enqueue(new Tuple(whatToLog, DateTime.Now));
}
}
The ConcurrentQueue will make sure that the queue-part will be thread safe.
The string s you construct will not make it more or less thread-safe
In the current form, you should instantiate the logger, and pass the reference to each thread that will use this class
Although thread-safe, it does not guarantee sequentiality of the items
Queues cannot grow infinitely, make sure that your mechanism to dequeue can keep up
Improvements:
Make the class static, easier access for several threads
Separate concerns on reading and writing; this can be done by making several essential function internal and placing classes in the same namespace
use C#6 string interpolation
Code with improvements
public static class Logger
{
private static ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public static void Log(string LogMessage)
{
// thread safe logging
queue.Enqueue($"{LogMessage} {DateTime.Now}");
}
//dequeue only within namespace
internal static string Dequeue() {
string dequeuedItem;
queue.TryDequeue(out dequeuedItem);
return dequeuedItem;
}
}
public class LoggerReader
{
public LoggerReader()
{
// create other objects here AND a thread that extracts
// from the queue and writes to a file
// because queue is thread safe this is perfectly ok
string logItem = Logger.Dequeue();
}
}
I would simply use a lock in the Log method (replace ConcurrentQueue by Queue), and would not worry about each instruction anymore, especially if the original logger is more complicated than the example here!
public void Log(string whatToLog)
{
lock(queue) {
string s = whatToLog + " " + DateTime.Now.ToString();
queue.Enqueue(s);
}
}
Edit: My bad, no strage events behavior. Error was somewhere else in code. Thx everybody for help. Please ignore this question
Please can someone explain to me what is happening here. I'm experiencing an unexpected event behaviour.
There is a singleton class:
internal class QueueListener
{
private static readonly object QueueChangeLock = new object();
private readonly List<IQueuedJobExecutioner> jobsQueue = new List<IQueuedJobExecutioner>();
// Here comes singleton private constructor, Instance property, all classic.
// Important line in constructor is this:
QueueManager.NewJobQueued += NewJobQueuedHandler;
private void NewJobQueuedHandler(object sender, NewJobQueuedEventArgs args)
{
lock (QueueChangeLock)
{
// This is the problematic place, note this!
jobsQueue.Add(args.QueuedJobExecutioner);
}
}
}
Now there is a second class:
public class QueueManager
{
public static event NewJobQueuedEventHandler NewJobQueued;
protected void RaiseNewJobQueuedEvent(IQueuedJobExecutioner queuedJobExecutioner)
{
if (NewJobQueued != null)
{
NewJobQueued(this, new NewJobQueuedEventArgs { QueuedJobExecutioner = queuedJobExecutioner });
}
}
}
Both classes reside on a server. Via WCF calls client executes sth like new QueueManager().MyMethod(), which calls RaiseNewJobQueuedEvent.
Everything works fine, however if two events are raised almost at the same time, I see in debugger the following at the problematic place (see comment in QueueListener):
First event comes. jobsQueue has no members.
jobsQueue.Add() is executed. jobsQueue has 1 member.
Second event comes. jobsQueue has no members! How? It's in a singleton and we just added a member!
jobsQueue.Add() is executed. jobsQueue has 1 member. Again. Member added in step 2 has been lost.
Not judging the design itself (it has some "historical" reasons), why exactly is this happening? Is this expected behavior and event somehow gets at some point a snapshot of jobsQueue or this is nonesense and I'm just missing some part of the puzzle?
Edit:
I'd say it is a singleton, and is implemented like this (these lines were omitted in original post):
class QueueListener
{
private static readonly object SyncRoot = new object();
private QueueListener()
{
//...
}
public static QueueListener Instance
{
get
{
if (instance == null)
{
lock (SyncRoot)
{
if (instance == null)
{
instance = new QueueListener();
}
}
}
return instance;
}
}
}
Yuval is correct, your class is not a singleton. A singleton is created when you have a public static method to create an instance and a private constructor. The private constructor ensures that the only way to create an instance is through the public method.
Please see https://msdn.microsoft.com/en-us/library/ff650316.aspx for more details.
Your QueueListener class is not actually a singleton. What that means for you is that you are creating multiple instances of it. To fix that you have to add the static keyword in the class declaration and declare a static constructor as well. Try changing your class to what is shown below:
internal static class QueueListener
{
private static readonly object QueueChangeLock = new object();
private static readonly List<IQueuedJobExecutioner> jobsQueue = new List<IQueuedJobExecutioner>();
// This is the singleton constructor that will be called
static QueueListener()
{
// Here comes singleton private constructor, Instance property, all classic.
// Important line in constructor is this:
QueueManager.NewJobQueued += NewJobQueuedHandler;
}
// Rest of class code...
}
Imagine this snippet:
using System;
public class Report {
static int Level=0;
public static void WriteLine(string Message) {
Console.WriteLine("{0}{1}",new String(' ',4*Level),Message);
}
public class Indent:IDisposable {
public Indent() { Report.WriteLine("{"); ++Level; }
void IDisposable.Dispose() { --Level; Report.WriteLine("}"); }
}
}
class Program {
static void Main() {
Report.WriteLine("Started");
Report.WriteLine("Calling submethod");
using(new Report.Indent()) {
Report.WriteLine("Submethod started");
using(new Report.Indent()) Report.WriteLine("Subsub, maybe?");
Report.WriteLine("Submethod reporting everything is fine");
Report.WriteLine("Submethod finished");
}
Report.WriteLine("Finished");
}
}
Which produces result:
Started
Calling submethod
{
Submethod started
{
Subsub, maybe?
}
Submethod reporting everything is fine
Submethod finished
}
Finished
Inside I'm using using(new Report.Indent()) instead of sticking to the only documented version I found, i.e. using(Report.Indent r=new Report.Indent()).
In my briefer version, however, can I be sure that Dispose() will always be called on those unnamed Indent objects, every time?
P.S.
// btw, I used word "anonymous" in the title, but I'm not sure that's what new objects that aren't assigned to any named variable should be called
Yes, using enures that even "anonymous objects" are always disposed of.
Internally, using stores whatever value was used when entering the block in local variable. This stored value is disposed when exiting the block.
I am trying to restrict access to an singletone object so only one thread
use it at time, Furthermore, I want to prevent from the same thread accessing twice
to the restricted code.
I tried the Lock method and i found out that its dosn't lock the thread that locked her, but only other threads..
as below:
public sealed class Singleton
{
private static readonly Singleton instance = new Singleton();
static Singleton()
{
}
private Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
public class SomeWorker
{
private readonly Timer _doWorkTimer = new Timer(20);
public SomeWorker()
{
InitiateTimer();
}
private void InitiateTimer()
{
_doWorkTimer .Elapsed += DoWorkElapse;
_doWorkTimer .Enabled = true;
}
private void DoWorkElapse(object source, ElapsedEventArgs e)
{
DoSomeWork();
}
private void DoSomeWork()
{
// I know that lock on string is wrong!
// Its just for the example only I
// Its just to make sure all the program is use the same lock..
lock ("ConnectionLock")
{
Console.WriteLine("Lock");
var inst = Singletone.Instance;
// Do Some Work on "inst" ...
Console.WriteLine("Unlock");
}
}
}
The result in the console for example is:
.
.
.
Lock
Unlock
Lock
Lock
Unlock
.
.
.
As we can see, 2 Lock comments shows one after another
So its mean that the "DoSomeWork()" accessed twice by the timer thread.
Anyone have any idea how to make this lock work?
Other Sync methods maby?
thanx.
You aren't doing your locking properly (and to top it off you are taking a lock on a string which is a big no-no). To save time, please read this article from Jon Skeet and implement one of the patterns to save yourself a headache.
In your code you have
public static Singletone Instance()
{
if (_instance == null)
{
lock (_instance)
{
if (_instance == null)
{
_instance = new Singletone ();
}
}
}
return _instance;;
}
Think about it. if (_instance == null) you do lock (_instance). So you lock using null. That's not good at all.
In MSDN lock Statement (C# Reference) the given example of how to use lock is:
class Account
{
decimal balance;
private Object thisLock = new Object();
public void Withdraw(decimal amount)
{
lock (thisLock)
{
if (amount > balance)
{
throw new Exception("Insufficient funds");
}
balance -= amount;
}
}
}
I guess you should follow it and have a separate object to use it as a lock.
And secondly, thread syncronization primitives are used to separate access to shared resources for different threads. If you need to separate access from one thread, you simply need to use flags. Something like this:
bool isBusy = false;
public static void Foo()
{
if (!isBusy)
{
isBusy = true;
try
{
//do the job
}
finally
{
isBusy = false;
}
}
}
Here you should understand that you simply skip the "locked-by-flag" code. On the contrary if you want to make the thread wait for itself, especially in a multithreading application, I guess it looks like it should be redesigned.
The easiest way to implement a singleton in .NET is:
public class Singleton : IDisposable
{
private readonly static Singleton _instance = new Singleton();
private readonly static object lockObject = new object();
static Singleton()
{
}
private Singleton()
{
InitiateConnection();
}
public static Singleton Instance
{
get { return _instance; }
}
/// <summary>
/// Method that accesses the DB.
/// </summary>
public void DoWork()
{
lock (lockObject)
{
//Do Db work here. Only one thread can execute these commands at a time.
}
}
~Singleton()
{
//Close the connection to DB.
//You don't want to make your singleton class implement IDisposable because
//you don't want to allow a call to Singleton.Instance.Dispose().
}
}
Read the excellent article on Singleton Pattern implementations in .NET that Bryan suggested in his answer. The above implementation is based on the fourth version described in the article. The CLR guarantees that the construction of the static field will thread-safe hence you do not need locking there. However you will need locking if your object has state (fields) that can be changed.
Note that there is a private readonly object used for ensuring mutual exclusion on the DoWork method. This way a single thread can call DoWork at a time. Also note that there is no way that the same thread can call this method twice at the same time since a thread executes instructions sequentially. The only way this method could be called twice from a single thread is if inside DoWork you call another method that eventually calls DoWork. I can't see the point of doing this and if you do then take care to avoid stack overflows. You could follow the suggestion of Konstantin and use a flag but IMHO you should redesign DoWork to do just one thing and avoid scenarios like these.
I am using a System.Threading.ThreadPool to manage a queue of jobs from a service. I have already implemented logging like this...
abstract class Global
{
public static LogFile LogFile = null;
}
public class LogFile : IDisposable
{
private StreamWriter sw;
public LogFile(string path){}
public void WriteEntry(string logText)
{
lock (sw)
{
sw.WriteLine(logText);
}
}
}
I want to create the log at service startup and use it from my queued worker threads.. something like this...
//On Service Start
Global.LogFile = new LogFile("log.txt");
//Kick of worker thread
ThreadPool.QueueUserWorkItem(objWrkrThread.CallbackMethod, iCount);
//Worker thread logs an entry in CallbackMethod()
Global.LogFile.WriteEntry("Hello World");
Is this safe? Will calling a method on a static instance of a class inadvertently 'synchronise' or 'block' my threads?
Michael
Nothing will 'synchronize' or 'block' unless you write code in your method. It doesn't matter whether it's an instance method or static method.
So by default, WriteEntry won't block any calls from your threads but it could very well corrupt file if you don't write the code to handle multiple simultaneous calls.
Read more on this topic here:
Are static methods thread safe
It's not safe to have multiple threads call WriteEntry at the same time unless it was designed to be safe.
What you are trying to do sounds like the perfect candidate for a Singleton class. I know it gets a bad wrap, but sometimes it's simplicity is worth it.
You can create a log class like this and you should be thread safe.
public sealed class Log
{
static Log instance=null;
static readonly object lockObject = new object();
static string path = "log.txt";
Log()
{
}
public static Log Instance
{
get
{
lock (lockObject)
{
if (instance==null)
{
instance = new Log();
}
return instance;
}
}
}
public void WriteLine(string message)
{
lock(lockObject)
{
using(StreamWriter sw = new StreamWriter(File.Open(path, FileMode.Append)))
{
sw.WriteLine(message);
}
}
}
}
Then in your code, you just call it like this:
Log executionLog = Log.Instance;
executionLog.WriteLine("this is a log message.");
You could also manage opening the file in similar thread safe methods to get rid of the over head of opening and closing the file every write.