I have a the following code setup
public interface ILogger
{
void WriteData(string Data);
}
public class Logger : ILogger
{
public void WriteData(string Data)
{
//Write to disk
}
}
public interface ILogic
{
void ProcessData(string Data);
}
public class Logic : ILogic
{
private ILogger Logger;
public Logic(ILogger Logger)
{
this.Logger = Logger;
}
public void ProcessData(string Data)
{
//Do stuff
Logger.WriteData("Data to write");
}
}
public class MainEntryPointClass
{
private BlockingCollection<string> DataInCollection;
private Task DataInTask;
private CancellationTokenSource CancellationTokenSource;
public Start()
{
InitializeDataIn();
}
private void InitializeDataIn()
{
CancellationTokenSource = new CancellationTokenSource();
DataInCollection = new BlockingCollection<DataInContents>();
DataInTask = Task.Factory.StartNew(() => ProcessDataIn(CancellationTokenSource.Token));
}
private void ProcessDataIn(CancellationToken CancelToken)
{
while (!CancelToken.IsCancellationRequested)
{
foreach (var item in DataInCollection.GetConsumingEnumerable())
{
Logic.ProcessData(item);
}
}
}
}
So I create a new Task in my main class and then data is added to the DataInCollection to queue up data as it comes in, we're talking every 30ms or so. This gets processed successfully.
I now want to write data to file on a separate thread just so if there is a disk problem the main logic checking isn't impacted. If there is a disk problem then the logic can continue. I'm just not sure where I do the file writing on the separate thread? Is it in the Main class, the Logic class or the Logger class?
It's Logger's responsibility to ensure that it doesn't block the caller. It can use many different strategies for that. You don't want to bake those strategies into the class that uses it.
I'd enqueue the message into a BlockingCollection<T>, and have a single IO thread write it out to the disk.
I also recommend imitating an existing logging interface, such as Common.Logging's ILog so you can easily switch to an existing logging framework if your "no third party" requirement gets ever lifted.
Something like:
class AsyncLogger:ILogger
{
public AsyncLogger(ILogger backingLogger)
{
new Thread(()=>
{
while(true)
{
var data=_queue.Take();
_backingLogger.WriteData(data);
}
}
).Start();
}
public void WriteData(string data)
{
_queue.Enqueue(data);
}
}
(I omitted stuff like a termination condition for IO thread, fields, handling of multiple loggers,...)
The Logger class is hopefully responsible for logging. So it seems like the right place to log the incoming data to disk.
Related
I guess it is sort of a code review, but here is my implementation of the producer / consumer pattern. What I would like to know is would there be a case in which the while loops in the ReceivingThread() or SendingThread() methods might stop executing. Please note that EnqueueSend(DataSendEnqeueInfo info) is called from multiple different threads and I probably can't use tasks here since I definitely have to consume commands in a separate thread.
private Thread mReceivingThread;
private Thread mSendingThread;
private Queue<DataRecievedEnqeueInfo> mReceivingThreadQueue;
private Queue<DataSendEnqeueInfo> mSendingThreadQueue;
private readonly object mReceivingQueueLock = new object();
private readonly object mSendingQueueLock = new object();
private bool mIsRunning;
EventWaitHandle mRcWaitHandle;
EventWaitHandle mSeWaitHandle;
private void ReceivingThread()
{
while (mIsRunning)
{
mRcWaitHandle.WaitOne();
DataRecievedEnqeueInfo item = null;
while (mReceivingThreadQueue.Count > 0)
{
lock (mReceivingQueueLock)
{
item = mReceivingThreadQueue.Dequeue();
}
ProcessReceivingItem(item);
}
mRcWaitHandle.Reset();
}
}
private void SendingThread()
{
while (mIsRunning)
{
mSeWaitHandle.WaitOne();
while (mSendingThreadQueue.Count > 0)
{
DataSendEnqeueInfo item = null;
lock (mSendingQueueLock)
{
item = mSendingThreadQueue.Dequeue();
}
ProcessSendingItem(item);
}
mSeWaitHandle.Reset();
}
}
internal void EnqueueRecevingData(DataRecievedEnqeueInfo info)
{
lock (mReceivingQueueLock)
{
mReceivingThreadQueue.Enqueue(info);
mRcWaitHandle.Set();
}
}
public void EnqueueSend(DataSendEnqeueInfo info)
{
lock (mSendingQueueLock)
{
mSendingThreadQueue.Enqueue(info);
mSeWaitHandle.Set();
}
}
P.S the idea here is that am using WaitHandles to put thread to sleep when the queue is empty, and signal them to start when new items are enqueued.
UPDATE
I am just going to leave this https://blogs.msdn.microsoft.com/benwilli/2015/09/10/tasks-are-still-not-threads-and-async-is-not-parallel/ ,for people who might be trying to implement Producer/Consumer pattern using TPL or tasks.
Use a BlockingCollection instead of Queue, EventWaitHandle and lock objects:
public class DataInfo { }
private Thread mReceivingThread;
private Thread mSendingThread;
private BlockingCollection<DataInfo> queue;
private CancellationTokenSource receivingCts = new CancellationTokenSource();
private void ReceivingThread()
{
try
{
while (!receivingCts.IsCancellationRequested)
{
// This will block until an item is added to the queue or the cancellation token is cancelled
DataInfo item = queue.Take(receivingCts.Token);
ProcessReceivingItem(item);
}
}
catch (OperationCanceledException)
{
}
}
internal void EnqueueRecevingData(DataInfo info)
{
// When a new item is produced, just add it to the queue
queue.Add(info);
}
// To cancel the receiving thread, cancel the token
private void CancelReceivingThread()
{
receivingCts.Cancel();
}
Personally, for simple producer-consumer problems, I would just use BlockingCollection. There would be no need to manually code your own synchronization logic. The consuming threads will also block if there are no items present in the queue.
Here is what your code might look like if you use this class:
private BlockingCollection<DataRecievedEnqeueInfo> mReceivingThreadQueue = new BlockingCollection<DataRecievedEnqeueInfo>();
private BlockingCollection<DataSendEnqeueInfo> mSendingThreadQueue = new BlockingCollection<DataSendEnqeueInfo>();
public void Stop()
{
// No need for mIsRunning. Makes the enumerables in the GetConsumingEnumerable() calls
// below to complete.
mReceivingThreadQueue.CompleteAdding();
mSendingThreadQueue.CompleteAdding();
}
private void ReceivingThread()
{
foreach (DataRecievedEnqeueInfo item in mReceivingThreadQueue.GetConsumingEnumerable())
{
ProcessReceivingItem(item);
}
}
private void SendingThread()
{
foreach (DataSendEnqeueInfo item in mSendingThreadQueue.GetConsumingEnumerable())
{
ProcessSendingItem(item);
}
}
internal void EnqueueRecevingData(DataRecievedEnqeueInfo info)
{
// You can also use TryAdd() if there is a possibility that you
// can add items after you have stopped. Otherwise, this can throw an
// an exception after CompleteAdding() has been called.
mReceivingThreadQueue.Add(info);
}
public void EnqueueSend(DataSendEnqeueInfo info)
{
mSendingThreadQueue.Add(info);
}
As suggested in comments, you also can give a try to the TPL Dataflow blocks.
As far as I can see, you have two similar pipelines, for receive and send, so I assume that your class hierarchy is like this:
class EnqueueInfo { }
class DataRecievedEnqeueInfo : EnqueueInfo { }
class DataSendEnqeueInfo : EnqueueInfo { }
We can assemble an abstract class which will encapsulate the logic for creating the pipeline, and providing the interface for processing the items, like this:
abstract class EnqueueInfoProcessor<T>
where T : EnqueueInfo
{
// here we will store all the messages received before the handling
private readonly BufferBlock<T> _buffer;
// simple action block for actual handling the items
private ActionBlock<T> _action;
// cancellation token to cancel the pipeline
public EnqueueInfoProcessor(CancellationToken token)
{
_buffer = new BufferBlock<T>(new DataflowBlockOptions { CancellationToken = token });
_action = new ActionBlock<T>(item => ProcessItem(item), new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = token
});
// we are linking two blocks so all the items from buffer
// will flow down to action block in order they've been received
_buffer.LinkTo(_action, new DataflowLinkOptions { PropagateCompletion = true });
}
public void PostItem(T item)
{
// synchronously wait for posting to complete
_buffer.Post(item);
}
public async Task SendItemAsync(T item)
{
// asynchronously wait for message to be posted
await _buffer.SendAsync(item);
}
// abstract method to implement
protected abstract void ProcessItem(T item);
}
Note that you also can encapsulate the link between two blocks by using the Encapsulate<TInput, TOutput> method, but in that case you have to properly handle the Completion of the buffer block, if you're using it.
After this, we just need to implement two methods for receive and send handle logic:
public class SendEnqueueInfoProcessor : EnqueueInfoProcessor<DataSendEnqeueInfo>
{
SendEnqueueInfoProcessor(CancellationToken token)
: base(token)
{
}
protected override void ProcessItem(DataSendEnqeueInfo item)
{
// send logic here
}
}
public class RecievedEnqueueInfoProcessor : EnqueueInfoProcessor<DataRecievedEnqeueInfo>
{
RecievedEnqueueInfoProcessor(CancellationToken token)
: base(token)
{
}
protected override void ProcessItem(DataRecievedEnqeueInfo item)
{
// recieve logic here
}
}
You also can create more complicated pipeline with TransformBlock<DataRecievedEnqeueInfo, DataSendEnqeueInfo>, if your message flow is about a ReceiveInfo message became SendInfo.
Our existing implementation of domain events limits (by blocking) publishing to one thread at a time to avoid reentrant calls to handlers:
public interface IDomainEvent {} // Marker interface
public class Dispatcher : IDisposable
{
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
// Subscribe code...
public void Publish(IDomainEvent domainEvent)
{
semaphore.Wait();
try
{
// Get event subscriber(s) from concurrent dictionary...
foreach (Action<IDomainEvent> subscriber in eventSubscribers)
{
subscriber(domainEvent);
}
}
finally
{
semaphore.Release();
}
}
// Dispose pattern...
}
If a handler publishes an event, this will deadlock.
How can I rewrite this to serialize calls to Publish? In other words, if subscribing handler A publishes event B, I'll get:
Handler A called
Handler B called
while preserving the condition of no reentrant calls to handlers in a multithreaded environment.
I do not want to change the public method signature; there's no place in the application to call a method to publish a queue, for instance.
We came up with a way to do it synchronously.
public class Dispatcher : IDisposable
{
private readonly ConcurrentQueue<IDomainEvent> queue = new ConcurrentQueue<IDomainEvent>();
private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
// Subscribe code...
public void Publish(IDomainEvent domainEvent)
{
queue.Enqueue(domainEvent);
if (IsPublishing)
{
return;
}
PublishQueue();
}
private void PublishQueue()
{
IDomainEvent domainEvent;
while (queue.TryDequeue(out domainEvent))
{
InternalPublish(domainEvent);
}
}
private void InternalPublish(IDomainEvent domainEvent)
{
semaphore.Wait();
try
{
// Get event subscriber(s) from concurrent dictionary...
foreach (Action<IDomainEvent> subscriber in eventSubscribers)
{
subscriber(domainEvent);
}
}
finally
{
semaphore.Release();
}
// Necessary, as calls to Publish during publishing could have queued events and returned.
PublishQueue();
}
private bool IsPublishing
{
get { return semaphore.CurrentCount < 1; }
}
// Dispose pattern for semaphore...
}
}
You will have to make Publish asynchronous to achieve that. Naive implementation would be as simple as:
public class Dispatcher : IDisposable {
private readonly BlockingCollection<IDomainEvent> _queue = new BlockingCollection<IDomainEvent>(new ConcurrentQueue<IDomainEvent>());
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
public Dispatcher() {
new Thread(Consume) {
IsBackground = true
}.Start();
}
private List<Action<IDomainEvent>> _subscribers = new List<Action<IDomainEvent>>();
public void AddSubscriber(Action<IDomainEvent> sub) {
_subscribers.Add(sub);
}
private void Consume() {
try {
foreach (var #event in _queue.GetConsumingEnumerable(_cts.Token)) {
try {
foreach (Action<IDomainEvent> subscriber in _subscribers) {
subscriber(#event);
}
}
catch (Exception ex) {
// log, handle
}
}
}
catch (OperationCanceledException) {
// expected
}
}
public void Publish(IDomainEvent domainEvent) {
_queue.Add(domainEvent);
}
public void Dispose() {
_cts.Cancel();
}
}
It can't be done with that interface. You can process the event subscriptions asynchronously to remove the deadlock while still running them serially, but then you can't guarantee the order you described. Another call to Publish might enqueue something (event C) while the handler for event A is running but before it publishes event B. Then event B ends up behind event C in the queue.
As long as Handler A is on equal footing with other clients when it comes to getting an item in the queue, it either has to wait like everyone else (deadlock) or it has to play fairly (first come, first served). The interface you have there doesn't allow the two to be treated differently.
That's not to say you couldn't get up to some shenanigans in your logic to attempt to differentiate them (e.g. based on thread id or something else identifiable), but anything along those lines would unreliable if you don't control the subscriber code as well.
I have created a class, SenderClass, which will start and run a background worker from its constructor.
The method, RunWorker(), runs is a while(true) loop which will pop elements from a queue, send them through the method SendMessage(), and sleep for a small amount of time to allow new elements to be added to the queue.
Here lies the problem: How do I test the method that sends the element from the queue, without exposing it to those who uses the class?
Implementation:
public class SenderClass : ISenderClass
{
private Queue<int> _myQueue = new Queue<int>();
private Thread _worker;
public SenderClass()
{
//Create a background worker
_worker = new Thread(RunWorker) {IsBackground = true};
_worker.Start();
}
private void RunWorker() //This is the background worker's method
{
while (true) //Keep it running
{
lock (_myQueue) //No fiddling from other threads
{
while (_myQueue.Count != 0) //Pop elements if found
SendMessage(_myQueue.Dequeue()); //Send the element
}
Thread.Sleep(50); //Allow new elements to be inserted
}
}
private void SendMessage(int element)
{
//This is what we want to test
}
public void AddToQueue(int element)
{
Task.Run(() => //Async method will return at ones, not slowing the caller
{
lock (_myQueue) //Lock queue to insert into it
{
_myQueue.Enqueue(element);
}
});
}
}
Wanted interface:
public interface ISenderClass
{
void AddToQueue(int element);
}
Needed interface for test purpose:
public interface ISenderClass
{
void SendMessage(int element);
void AddToQueue(int element);
}
There's a very simple solution, saying I have created my class incorrect due to the Single Responsability Principle, and my class' purpose is not to send messages, but actually run what sends them.
What I should have, is another class, TransmittingClass, which exposes the method SendMessage(int) through its own interface.
This way I can test that class, and SenderClass should just call the method through that interface.
But what other options do I have with the current implementation?
I can make all private methods I wish to test (all of them) have a [assembly:InternalsVisibleTo("MyTests")], but does a third option exist?
Send message logic should be implemented in a separate class with a separate interface. This class should take the new class as a dependency. You can test the new class separately.
public interface IMessageQueue
{
void AddToQueue(int element);
}
public interface IMessageSender
{
void SendMessage(object message);
}
public class SenderClass : IMessageQueue
{
private readonly IMessageSender _sender;
public SenderClass(IMessageSender sender)
{
_sender = sender;
}
public void AddToQueue(int element)
{
/*...*/
}
private void SendMessage()
{
_sender.SendMessage(new object());
}
}
public class DummyMessageSender : IMessageSender
{
//you can use this in your test harness to check for the messages sent
public Queue<object> Messages { get; private set; }
public DummyMessageSender()
{
Messages = new Queue<object>();
}
public void SendMessage(object message)
{
Messages.Enqueue(message);
//obviously you'll need to do some locking here too
}
}
Edit
To address your comment, here is an implementation using Action<int>. This allows you to define your message sending action in your test class to mock the SendMessage method without worrying about creating another class. (Personally, I'd still prefer to define the classes/interfaces explicitly).
public class SenderClass : ISenderClass
{
private Queue<int> _myQueue = new Queue<int>();
private Thread _worker;
private readonly Action<int> _senderAction;
public SenderClass()
{
_worker = new Thread(RunWorker) { IsBackground = true };
_worker.Start();
_senderAction = DefaultMessageSendingAction;
}
public SenderClass(Action<int> senderAction)
{
//Create a background worker
_worker = new Thread(RunWorker) { IsBackground = true };
_worker.Start();
_senderAction = senderAction;
}
private void RunWorker() //This is the background worker's method
{
while (true) //Keep it running
{
lock (_myQueue) //No fiddling from other threads
{
while (_myQueue.Count != 0) //Pop elements if found
SendMessage(_myQueue.Dequeue()); //Send the element
}
Thread.Sleep(50); //Allow new elements to be inserted
}
}
private void SendMessage(int element)
{
_senderAction(element);
}
private void DefaultMessageSendingAction(int item)
{
/* whatever happens during sending */
}
public void AddToQueue(int element)
{
Task.Run(() => //Async method will return at ones, not slowing the caller
{
lock (_myQueue) //Lock queue to insert into it
{
_myQueue.Enqueue(element);
}
});
}
}
public class TestClass
{
private SenderClass _sender;
private Queue<int> _messages;
[TestInitialize]
public void SetUp()
{
_messages = new Queue<int>();
_sender = new SenderClass(DummyMessageSendingAction);
}
private void DummyMessageSendingAction(int item)
{
_messages.Enqueue(item);
}
[TestMethod]
public void TestMethod1()
{
//This isn't a great test, but I think you get the idea
int message = 42;
_sender.AddToQueue(message);
Thread.Sleep(100);
CollectionAssert.Contains(_messages, 42);
}
}
It looks like SenderClass should not perform any sending at all. It should simply maintain the queue. Inject an Action<int> through the constructor that does the sending. That way you can move SendMessage somewhere else and call it however you like.
As an added benefit your test of SendMessage is not cluttered with queue management.
Seeing your edit you don't seem to like this approach and you don't seem to like the InternalsVisibleTo approach either. You could expose SendMessage through a separate interface and implement that interface explicitly. That way SendMessage is still callable through that interface but by default it is not accessible without some casting contortions. It also does not show up in the intellisense autocomplete list.
I have an application, that use Spring.AOP library to apply proxy-object to log what methods of program do (I use xml-configuration). Before I used log4net to log messages with Spring.AOP(simplified class):
public class CommandLoggingAdvice : IMethodInterceptor
{
// here I get an instance of log4net
private ILog _Logger = null;
protected ILog Logger
{
_Logger = LogManager.GetLogger("Logger1");
}
public object Invoke(IMethodInvocation invocation)
{
Logger1.Info("Now we enter to method");
// here i call the method
object returnValue = invocation.Proceed();
Logger1.Info("Now we exit from method");
return returnValue;
}
}
But there were a problem: I needed to use a queue of messages, which should work in independent thread to distribute program load on several thread
Here is a new Spring.AOP class:
public class CommandLoggingAdvice : IMethodInterceptor
{
private static ProducerConsumerClass LoggingQueue = ProducerConsumerClass.Instance;
public object Invoke(IMethodInvocation invocation)
{
LoggingQueue.AddTask("Now we enter to method");
// here I call the method
object returnValue = invocation.Proceed();
LoggingQueue.AddTask("Now we exit from method");
return returnValue;
}
}
/// <summary>
/// ProducerConsumerClass implements:
/// - SingleTon-object, Producer/Consumer queue (queue is a FIFO BlockingCollection) - I need this class to process all messages, which come from CommonLoggingAdvice class. The reason is that I need to do it in independent thread (.IsBackground = false)
/// - This version of Singleton class is threadsafe
/// </summary>
public sealed class ProducerConsumerClass : IDisposable
{
// here Iget an instance of log4net
private ILog _Logger = null;
protected ILog Logger
{
_Logger = LogManager.GetLogger("Logger1");
}
private BlockingCollection<string> tasks = new BlockingCollection<string>();
private static volatile ProducerConsumerClass _instance;
private static object locker = new object();
Thread worker;
private ProducerConsumerClass()
{
worker = new Thread(Work);
worker.Name = "Queue thread";
worker.IsBackground = false;
worker.Start();
}
public static ProducerConsumerClass Instance
{
get
{
if (_instance == null)
{
lock (locker)
{
if (_instance == null)
{
_instance = new ProducerConsumerClass();
}
}
}
return _instance;
}
}
public void AddTask(string task)
{
tasks.Add(task);
}
// now this is unused method
// I need to call this method somehow at the end of program, but cross-cutting concern doesn't allow to do it straightahead
public void Dispose()
{
tasks.CompleteAdding();
worker.Join();
tasks.Dispose();
}
void Work()
{
while (true)
{
string task = null;
if (!tasks.IsCompleted)
{
Thread.Sleep(1000);
task = tasks.Take();
Logger1.Info(worker.Name + " " + task );
}
else
{
return;
}
}
}
}
So this class is always running (and so the "worker" thread);
if "tasks" is empty, - tasks.Take() forces "worker" thread to pause until something will be added using tasks.Add().
But when all functions of program are ended and i need to exit from program - "tasks" is empty and "worker" is paused - so I can not exit from infinite cycle => program never ends.
As long as Spring.AOP classes are cross-cutting and they apply automatically, I don't know how to tell "worker" thread ( method Work() ) that it should be completed ( CompleteAdding() method , or Dispose() ).
Could you help me with this problem or tell any other ways to do what I need:
cross-cutting concern with Spring.AOP for logging
threadsafe implemenation of Singleton-class with queue(or Producer/consumer pattern) in independent thread, which live as long as lives application and a little more: until the queue is empty.
You can use a independent thread to write your log in a queue. Using lock to solve your needs about write in your queue.
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?
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.
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.
public static class SingletonLoggingService
{
public static ILoggingService LoggingService = ObjectBuilder.GetObjectByName("LoggingService");
}
SingletonLoggingService.LoggingService.Info("Test");
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);
}