What is the best design to this class? - c#

assume this class:
public class Logger
{
static TextWriter fs = null;
public Logger(string path)
{
fs = File.CreateText(path);
}
public static void Log(Exception ex)
{
///do logging
}
public static void Log(string text)
{
///do logging
}
}
and I have to use this like:
Logger log = new Logger(path);
and then use Logger.Log() to log what I want. I just use one Logger.
the question is: is this a good design? to instantiate a class and then always call it's static method? any suggestion yield in better design is appreciated.
Edit based on Marc's answer:
I flush on the last line of Log and there is no need for me to read the file while it is open, the issue with file not cleanly closed is right. this class simply satisfy my requirements and there is no need to be thread safe for it. I just want to get read of the instantiation part, I should get into the SetPath you said, any suggestion for closing file?

Yes, having a constructor just for this is bad design. A static SetPath method that can only be called once (else throws an exception) would seem better. You would set the path during app-startup, etc.
Then you can either make it a static class, or a singleton if it is required to satisfy some interface-based scenario.
Next: you must add synchronisation here! That is not thread safe. If two threads attempt to log at the same time, I would expect this to collapse horribly. It doesn't need to be complex; at the simplest:
private readonly object syncLock = new object();
public static void Log(string value) {
lock(syncLock) {
//...
}
}
(but note that this may incur some blocking costs; which can be improved with more sophisticated code - see below)
There are existing logging libraries that will think of lots more issues - file partitioning, async (to stop your code being blocked by IO), batching, etc; why not just use one of them? In particular, at te moment your file will not be cleanly closed at app-exit, doesn't flush regularly, and will keep the file locked most of the time. Not good.

No, this doesn't make sense. Each time a Logger is instantiated, the static TextWriter will be overwritten, which will affect all consumers of the class. If you want to keep the instance constructor then you should make the TextWriter an instance field and the methods should be instance methods.
As an alternative, you may want to consider using log4net, which will do this kind of logging work for you.

I think you should make whole class static with static property allowing you to set up the log path.
public static class Logger
{
static TextWriter fs = null;
public static string FileName
{
set
{
fs = File.CreateText(value);
}
}
public static void Log(Exception ex)
{
if(fs == null) return;
///do logging
}
public static void Log(string text)
{
if(fs == null) return;
///do logging
}
}

Related

c# can the same file writer singleton be used to write to multiple files at the same time

For instance, Can I make a singleton that writes to files and then use this in multiple threads to write to different files at the same time? Or is there some unwanted side effect I'm not thinking about? This is difficult to test out every scenario in a demo app so was hoping for some guidance. The Singleton File writer looks like this.
public sealed class CustomFileWriter
{
private static CustomFileWriter(){}
public static CustomFileWriter Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new CustomFileWriter();
}
return instance;
}
}
}
WriteToFile(string fileName, string contents)
{
// other business logic goes here that is not specific to the question.
File.AppendAllText(fileName, contents)
}
}

Static logger class consideration

I've found out some logger class and I am not so sure whether this class is really thread safe. True is that the Log method implements lock but access to class itself by multi threads will not raise problems? It consider me becase TextWriter tw is static so it means class has only one copy of tw and during each thread will access it can raise problems or not? BTW please take a look do you have any other objections here?:
public static class Logger
{
static readonly TextWriter tw;
private static readonly object _syncObject = new object();
static Logger(string SPath)
{
tw = TextWriter.Synchronized(File.AppendText(SPath + "\\Log.txt"));
}
public static void Write(string logMessage)
{
try
{
Log(logMessage, tw);
}
catch (IOException e)
{
tw.Close();
}
}
public static void Log(string logMessage, TextWriter w) {
// only one thread can own this lock, so other threads
// entering this method will wait here until lock is
// available.
lock(_syncObject) {
w.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
DateTime.Now.ToLongDateString());
w.WriteLine(" :");
w.WriteLine(" :{0}", logMessage);
w.WriteLine("-------------------------------");
// Update the underlying file.
w.Flush();
}
}
}
Second version for further dicsuss purposes:
public static class Logger
{
static StreamWriter sw;
private static readonly object _syncObject = new object();
static Logger(string SPath)
{
lock(_syncObject)
{
StreamWriter sw = File.AppendText(SPath));
}
}
....
It is thread safe because every path uses the Log static method which uses a lock on the static _syncObject. This means that every thread that attempts to Log(..) will block if somebody else is logging.
However, if you call the Log method directly rather than the Write method, and you pass in a TextWriter that is being used by other threads, then that's not safe.
First of all, TextWriter is an abstract class, so the real instance might be any derived class. The documentation on TextWriter doesn't guarantee thread-safety of TextWriter implementation:
Any instance members are not guaranteed to be thread safe.
There is no guarantee that external lock will bring the thread-safety. For example, the implementation may use thread-local storage for its internal data. TextWriter.Flush may or may not help, depending on the implementation (but you never know which implementation comes into Log method and whether this implementation was e. g. created under the same lock).
This all is about Log method.
The usage of Write, on the contrary, seems to be good: it uses TextWriter.Synchronized, which is thread-safe, according to the documentation:
Creates a thread-safe wrapper around the specified TextWriter.
But take into account, that thread-safety of the synchronized text writer may or may not be the thread safety you need: if you are making to consecutive calls to Log, the results are not guaranteed to be consecutive in the output file.

Multithreading, generic locks

I have a singleton class which looks a lot like this,
public class CfgHandler
{
private static readonly string ConfigDir = "Config";
public T Get<T>() where T : class, new()
{
string cfgFile = Path.Combine(ConfigDir, typeof(T).FullName + ".json");
if (File.Exists(cfgFile))
{
var reader = new JsonReader();
return reader.Read<T>(File.ReadAllText(cfgFile));
}
return null;
}
public void Set<T>(T instance) where T : class, new()
{
string cfgFile = Path.Combine(ConfigDir, typeof(T).FullName + ".json");
var writer = new JsonWriter();
string json = writer.Write(instance);
File.WriteAllText(cfgFile, json);
}
}
The class is used in a multithreaded environment and I want to add locks. But not one lock for the whole class, since I don't want a race condition between cfg.Set<Foo>(); and cfg.Set<Bar>() as they work with different data.
I've thought about adding the following class to CfgHandler,
private static class Locks<T>
{
private static object _lock = new object();
public static object Lock { get { return _lock; } }
}
and then lock like this (both for Get and Set),
public void Set<T>(T instance) where T : class, new()
{
lock(Locks<T>.Lock)
{
// save to disk
}
}
Am I missing something trivial? Is there a better way of achieving my goal?
Lock per instance or lock per type?
The way you are doing it (with a static Locks<T>.Lock) means that every call to Set<Foo> even on a different instance of CfgHandler will share the same lock. Is that what you want? I'm guessing you may be better off just locking per instance - it will save you the complexity of Locks<T>. Just declare a private instance member (private object _lock = new object();) and use it (lock(this._lock))
EDIT If you're using a singleton instance of CfgHandler and want to lock per type, then I guess your approach is perfectly fine. If you're not using a single instance, but still want to lock per type then just make sure to use an instance of Locks<T> instead of making it static.
Please see my question here for more details: Are static members of generic classes shared between types
The implementation you have is simple but effective, it will prevent concurrent access to the Set<T>(T Instance) call correctly. My only advice is that the lock duration should be limited if you are making many concurrent calls to this API. For instance you could do all the work, but then only lock the call to the writer.write(instance) call, which is the only non-threadsafe work you appear to be doing in the call.
As an aside you have the potential to improve your code on the Get call, please see my answer here Is there a way to check if a file is in use? regarding your check for the file existing.

C# thread safety of global configuration settings

In a C# app, suppose I have a single global class that contains some configuration items, like so :
public class Options
{
int myConfigInt;
string myConfigString;
..etc.
}
static Options GlobalOptions;
the members of this class will be uses across different threads :
Thread1: GlobalOptions.myConfigString = blah;
while
Thread2: string thingie = GlobalOptions.myConfigString;
Using a lock for access to the GlobalOptions object would also unnecessary block when 2 threads are accessing different members, but on the other hand creating a sync-object for every member seems a bit over the top too.
Also, using a lock on the global options would make my code less nice I think;
if I have to write
string stringiwanttouse;
lock(GlobalOptions)
{
stringiwanttouse = GlobalOptions.myConfigString;
}
everywhere (and is this thread-safe or is stringiwanttouse now just a pointer to myConfigString ? Yeah, I'm new to C#....) instead of
string stringiwanttouse = GlobalOptions.myConfigString;
it makes the code look horrible.
So...
What is the best (and simplest!) way to ensure thread-safety ?
You could wrap the field in question (myConfigString in this case) in a Property, and have code in the Get/Set that uses either a Monitor.Lock or a Mutex. Then, accessing the property only locks that single field, and doesn't lock the whole class.
Edit: adding code
private static object obj = new object(); // only used for locking
public static string MyConfigString {
get {
lock(obj)
{
return myConfigstring;
}
}
set {
lock(obj)
{
myConfigstring = value;
}
}
}
The following was written before the OP's edit:
public static class Options
{
private static int _myConfigInt;
private static string _myConfigString;
private static bool _initialized = false;
private static object _locker = new object();
private static void InitializeIfNeeded()
{
if (!_initialized) {
lock (_locker) {
if (!_initialized) {
ReadConfiguration();
_initalized = true;
}
}
}
}
private static void ReadConfiguration() { // ... }
public static int MyConfigInt {
get {
InitializeIfNeeded();
return _myConfigInt;
}
}
public static string MyConfigString {
get {
InitializeIfNeeded();
return _myConfigstring;
}
}
//..etc.
}
After that edit, I can say that you should do something like the above, and only set configuration in one place - the configuration class. That way, it will be the only class modifying the configuration at runtime, and only when a configuration option is to be retrieved.
Your configurations may be 'global', but they should not be exposed as a global variable. If configurations don't change, they should be used to construct the objects that need the information - either manually or through a factory object. If they can change, then an object that watches the configuration file/database/whatever and implements the Observer pattern should be used.
Global variables (even those that happen to be a class instance) are a Bad Thing™
What do you mean by thread safety here? It's not the global object that needs to be thread safe, it is the accessing code. If two threads write to a member variable near the same instant, one of them will "win", but is that a problem? If your client code depends on the global value staying constant until it is done with some unit of processing, then you will need to create a synchronization object for each property that needs to be locked. There isn't any great way around that. You could just cache a local copy of the value to avoid problems, but the applicability of that fix will depend on your circumstances. Also, I wouldn't create a synch object for each property by default, but instead as you realize you will need it.

'using' statement vs 'try finally'

I've got a bunch of properties which I am going to use read/write locks on. I can implement them either with a try finally or a using clause.
In the try finally I would acquire the lock before the try, and release in the finally. In the using clause, I would create a class which acquires the lock in its constructor, and releases in its Dispose method.
I'm using read/write locks in a lot of places, so I've been looking for ways that might be more concise than try finally. I'm interested in hearing some ideas on why one way may not be recommended, or why one might be better than another.
Method 1 (try finally):
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
rwlMyLock_m .AcquireReaderLock(0);
try
{
return dtMyDateTime_m
}
finally
{
rwlMyLock_m .ReleaseReaderLock();
}
}
set
{
rwlMyLock_m .AcquireWriterLock(0);
try
{
dtMyDateTime_m = value;
}
finally
{
rwlMyLock_m .ReleaseWriterLock();
}
}
}
Method 2:
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m
public DateTime MyDateTime
{
get
{
using (new ReadLock(rwlMyLock_m))
{
return dtMyDateTime_m;
}
}
set
{
using (new WriteLock(rwlMyLock_m))
{
dtMyDateTime_m = value;
}
}
}
public class ReadLock : IDisposable
{
private ReaderWriterLock rwl;
public ReadLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireReaderLock(0);
}
public void Dispose()
{
rwl.ReleaseReaderLock();
}
}
public class WriteLock : IDisposable
{
private ReaderWriterLock rwl;
public WriteLock(ReaderWriterLock rwl)
{
this.rwl = rwl;
rwl.AcquireWriterLock(0);
}
public void Dispose()
{
rwl.ReleaseWriterLock();
}
}
From MSDN, using Statement (C# Reference)
The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
So basically, it is the same code but with a nice automatic null-checks and an extra scope for your variable. The documentation also states that it "ensures the correct use of IDisposable object" so you might as well gets even better framework support for any obscure cases in the future.
So go with option 2.
Having the variable inside a scope that ends immediately after it's no longer needed is also a plus.
I definitely prefer the second method. It is more concise at the point of usage, and less error prone.
In the first case someone editing the code has to be careful not to insert anything between the Acquire(Read|Write)Lock call and the try.
(Using a read/write lock on individual properties like this is usually overkill though. They are best applied at a much higher level. A simple lock will often suffice here since the possibility of contention is presumably very small given the time the lock is held for, and acquiring a read/write lock is a more expensive operation than a simple lock).
Consider the possibility that both solutions are bad because they mask exceptions.
A try without a catch should obviously be a bad idea; see MSDN for why the using statement is likewise dangerous.
Note also Microsoft now recommends ReaderWriterLockSlim instead of ReaderWriterLock.
Finally, note that the Microsoft examples use two try-catch blocks to avoid these issues, e.g.
try
{
try
{
//Reader-writer lock stuff
}
finally
{
//Release lock
}
}
catch(Exception ex)
{
//Do something with exception
}
A simple, consistent, clean solution is a good goal, but assuming you can't just use lock(this){return mydateetc;}, you might reconsider the approach; with more info I'm sure Stack Overflow can help ;-)
I personally use the C# "using" statement as often as possible, but there are a few specific things that I do along with it to avoid the potential issues mentioned. To illustrate:
void doSomething()
{
using (CustomResource aResource = new CustomResource())
{
using (CustomThingy aThingy = new CustomThingy(aResource))
{
doSomething(aThingy);
}
}
}
void doSomething(CustomThingy theThingy)
{
try
{
// play with theThingy, which might result in exceptions
}
catch (SomeException aException)
{
// resolve aException somehow
}
}
Note that I separate the "using" statement into one method and the use of the object(s) into another method with a "try"/"catch" block. I may nest several "using" statements like this for related objects (I sometimes go three or four deep in my production code).
In my Dispose() methods for these custom IDisposable classes, I catch exceptions (but NOT errors) and log them (using Log4net). I have never encountered a situation where any of those exceptions could possibly affect my processing. The potential errors, as usual, are allowed to propagate up the call stack and typically terminate processing with an appropriate message (the error and stack trace) logged.
If I somehow encountered a situation where a significant exception could occur during Dispose(), I would redesign for that situation. Frankly, I doubt that will ever happen.
Meanwhile, the scope and cleanup advantages of "using" make it one of my most favorite C# features. By the way, I work in Java, C#, and Python as my primary languages, with lots of others thrown in here and there, and "using" is one of my most favorite language features all around because it is a practical, everyday workhorse.
I like the 3rd option
private object _myDateTimeLock = new object();
private DateTime _myDateTime;
public DateTime MyDateTime{
get{
lock(_myDateTimeLock){return _myDateTime;}
}
set{
lock(_myDateTimeLock){_myDateTime = value;}
}
}
Of your two options, the second option is the cleanest and easier to understand what's going on.
"Bunch of properties" and locking at the property getter and setter level looks wrong. Your locking is much too fine-grained. In most typical object usage, you'd want to make sure that you acquired a lock to access more than one property at the same time. Your specific case might be different but I kinda doubt it.
Anyway, acquiring the lock when you access the object instead of the property will significantly cut down on the amount of locking code you'll have to write.
DRY says: second solution. The first solution duplicates the logic of using a lock, whereas the second does not.
Try/Catch blocks are generally for exception handling, while using blocks are used to ensure that the object is disposed.
For the read/write lock a try/catch might be the most useful, but you could also use both, like so:
using (obj)
{
try { }
catch { }
}
so that you can implicitly call your IDisposable interface as well as make exception handling concise.
The following creates extension methods for the ReaderWriterLockSlim class that allow you to do the following:
var rwlock = new ReaderWriterLockSlim();
using (var l = rwlock.ReadLock())
{
// read data
}
using (var l = rwlock.WriteLock())
{
// write data
}
Here's the code:
static class ReaderWriterLockExtensions() {
/// <summary>
/// Allows you to enter and exit a read lock with a using statement
/// </summary>
/// <param name="readerWriterLockSlim">The lock</param>
/// <returns>A new object that will ExitReadLock on dispose</returns>
public static OnDispose ReadLock(this ReaderWriterLockSlim readerWriterLockSlim)
{
// Enter the read lock
readerWriterLockSlim.EnterReadLock();
// Setup the ExitReadLock to be called at the end of the using block
return new OnDispose(() => readerWriterLockSlim.ExitReadLock());
}
/// <summary>
/// Allows you to enter and exit a write lock with a using statement
/// </summary>
/// <param name="readerWriterLockSlim">The lock</param>
/// <returns>A new object that will ExitWriteLock on dispose</returns>
public static OnDispose WriteLock(this ReaderWriterLockSlim rwlock)
{
// Enter the write lock
rwlock.EnterWriteLock();
// Setup the ExitWriteLock to be called at the end of the using block
return new OnDispose(() => rwlock.ExitWriteLock());
}
}
/// <summary>
/// Calls the finished action on dispose. For use with a using statement.
/// </summary>
public class OnDispose : IDisposable
{
Action _finished;
public OnDispose(Action finished)
{
_finished = finished;
}
public void Dispose()
{
_finished();
}
}
I think method 2 would be better.
Simpler and more readable code in your properties.
Less error-prone since the locking code doesn't have to be re-written several times.
While I agree with many of the above comments, including the granularity of the lock and questionable exception handling, the question is one of approach. Let me give you one big reason why I prefer using over the try {} finally model... abstraction.
I have a model very similar to yours with one exception. I defined a base interface ILock and in it I provided one method called Acquire(). The Acquire() method returned the IDisposable object and as a result means that as long as the object I am dealing with is of type ILock that it can be used to do a locking scope. Why is this important?
We deal with many different locking mechanisms and behaviors. Your lock object may have a specific timeout that employs. Your lock implementation may be a monitor lock, reader lock, writer lock or spin lock. However, from the perspective of the caller all of that is irrelevant, what they care about is that the contract to lock the resource is honored and that the lock does it in a manner consistent with it's implementation.
interface ILock {
IDisposable Acquire();
}
class MonitorLock : ILock {
IDisposable Acquire() { ... acquire the lock for real ... }
}
I like your model, but I'd consider hiding the lock mechanics from the caller. FWIW, I've measured the overhead of the using technique versus the try-finally and the overhead of allocating the disposable object will have between a 2-3% performance overhead.
I'm surprised no one has suggested encapsulating the try-finally in anonymous functions. Just like the technique of instantiating and disposing of classes with the using statement, this keeps the locking in one place. I prefer this myself only because I'd rather read the word "finally" than the word "Dispose" when I'm thinking about releasing a lock.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
rwlMyLock_m,
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
rwlMyLock_m,
delegate () { dtMyDateTime_m = value; }
);
}
}
private static DateTime ReadLockedMethod(
ReaderWriterLock rwl,
ReadLockMethod method
)
{
rwl.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwl.ReleaseReaderLock();
}
}
private static void WriteLockedMethod(
ReaderWriterLock rwl,
WriteLockMethod method
)
{
rwl.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwl.ReleaseWriterLock();
}
}
}
SoftwareJedi, I don't have an account, so I can't edit my answers.
In any case, the previous version wasn't really good for general purpose use since the read lock always required a return value. This fixes that:
class StackOTest
{
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
DateTime retval = default(DateTime);
ReadLockedMethod(
delegate () { retval = dtMyDateTime_m; }
);
return retval;
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private void ReadLockedMethod(Action method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(Action method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}
Actually in your first example, to make the solutions comparable, you would also implement IDisposable there as well. Then you'd call Dispose() from the finally block instead of releasing the lock directly.
Then you'd be "apples to apples" implementation (and MSIL)-wise (MSIL will be the same for both solutions). It's still probably a good idea to use using because of the added scoping and because the Framework will ensure proper usage of IDisposable (the latter being less beneficial if you're implementing IDisposable yourself).
Silly me. There's a way to make that even simpler by making the locked methods part of each instance (instead of static like in my previous post). Now I really prefer this because there's no need to pass `rwlMyLock_m' off to some other class or method.
class StackOTest
{
private delegate DateTime ReadLockMethod();
private delegate void WriteLockMethod();
static ReaderWriterLock rwlMyLock_m = new ReaderWriterLock();
private DateTime dtMyDateTime_m;
public DateTime MyDateTime
{
get
{
return ReadLockedMethod(
delegate () { return dtMyDateTime_m; }
);
}
set
{
WriteLockedMethod(
delegate () { dtMyDateTime_m = value; }
);
}
}
private DateTime ReadLockedMethod(ReadLockMethod method)
{
rwlMyLock_m.AcquireReaderLock(0);
try
{
return method();
}
finally
{
rwlMyLock_m.ReleaseReaderLock();
}
}
private void WriteLockedMethod(WriteLockMethod method)
{
rwlMyLock_m.AcquireWriterLock(0);
try
{
method();
}
finally
{
rwlMyLock_m.ReleaseWriterLock();
}
}
}

Categories

Resources