The point of all this is to run a separate Thread ( can be something similar: Task, Action ) and to log the "start" and the "end", preferably minimizing code impact (changes) and logging being transparent to the code, just using a different class.
Recently I decided to inherit from class System.Threading.Thread as a way to implement logging for things like "Thread x started." and "Thread x ended." to a file, for debugging.
Since the class is sealed I used composition to add the Thread as a member and call respective function, accessors and all necessary.
I had a simplistic idea of how to do it so I thought something like
namespace MyNamespace
{
class Thread
{
private System.Threading.Thread thread;
//wrap constructor properties methods...
//...
public void Start()
{
log(thread.name + " start.");
thread.Start();
log(thread.name + " end.");
}
//...
}
}
Now after all this trouble of wrapping existing functionality (and using the new namespace instead of System.Threading)... this turned out to be bad since this call if I'm not mistaking is from the calling Thread and second the "end" does not log. The logging is mainly for debugging and having a non-volatile state of what happened.
EDIT:
Here's a simplified code using Ahmed's answer, which is good, and still ongoing issue is that if the SimulatedThread throws an exception the "Ending..." doesn't log for either "MainThread" or "CustomThread".
If the CustomThread abnormally terminates, "Ending..." for "MainThread" and "CustomThread" should be recorded. ( The exception handling is not relevant ). "MainThread" should be bulletproof from "CustomThread".
Full implementation
using System;
using System.Security;
using System.Threading;
namespace CS_Tests_Console
{
class Program
{
static void Main(string[] args)
{
Logger.Log("Starting...");
try
{
Thread.CurrentThread.Name = "MainThread";
CustomThread thread = new CustomThread(SimulateThread)
{
Name = "CustomThread",
};
thread.Start();
thread.Join();
}
catch (Exception ex)
{
Logger.Log("Cought exception:" + ex.ToString());
}
Logger.Log("Ending...");
}
private static void SimulateThread()
{
Logger.Log("Running...");
Thread.Sleep(2000);
throw new Exception("Test Exception");
}
}
public static class Logger
{
public static void Log(String message)
{
if (Thread.CurrentThread.Name == null)
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " Thread.CurrentThread.Name is NULL -> " + message);
}
else
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " " + Thread.CurrentThread.Name + " -> " + message);
}
}
}
public class CustomThread
{
public Thread threadInstance { get; private set; }
public CustomThread(ThreadStart threadStart)
{
threadInstance = new Thread(() =>
{
Logger.Log("Starting...");
threadStart();
Logger.Log("Ending...");
});
}
public string Name { get { return threadInstance.Name; } set { threadInstance.Name = value; } }
[SecuritySafeCritical]
public void Join()
{
threadInstance.Join();
}
public void Start()
{
threadInstance.Start();
}
}
}
Encapsulate logging in the ThreadStart delegate:
public class Logger{
public void Log(String message){
Console.WriteLine(message);
}
}
public class CustomThread {
public Thread ThreadInst { get; private set; }
public Logger logger = new Logger();
public CustomThread(ThreadStart threadStart) {
ThreadInst = new Thread(() =>
{
logger.Log(Thread.CurrentThread.Name + " Starting...");
threadStart();
logger.Log(Thread.CurrentThread.Name + " Ending...");
});
}
public void Start() { ThreadInst.Start(); }
}
class Program
{
static void Main(string[] args)
{
new CustomThread(() => Thread.Sleep(2000)).Start();
}
}
Edit: Added catching and logging exceptions:
public CustomThread(ThreadStart threadStart) {
ThreadInst = new Thread(() =>
{
logger.Log(Thread.CurrentThread.Name + " Starting...");
try {
threadStart();
} catch (Exception ex) {
logger.Log("Error in thread" + Thread.CurrentThread.Name + " " + ex.Message);
}
logger.Log(Thread.CurrentThread.Name + " Ending...");
});
}
Related
I'm doing a small windows service, it reads from a web service and stores the data in a local database, however, it does not finish executing the while (while it's a service), when I'm debugging it in vs 15 it works perfectly , Follow the code below.
PS: The code I used to debug I comment it before it starts, it arrives to enter the while, but only the first line and does not check the rest.
Program.cs
using System.ServiceProcess;
namespace rdi_server.service
{
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
Service1.CS
using System;
using System.Configuration;
using System.ServiceProcess;
using System.Threading;
namespace rdi_server.service
{
public partial class Service1 : ServiceBase
{
private Thread _thread;
private Updater _updater = new Updater();
private readonly int Interval = Convert.ToInt32(ConfigurationManager.AppSettings["timer"]);
private readonly string Connection = ConfigurationManager.AppSettings["connection"];
private readonly Connector _usuarioConnector;
private readonly Connector _bandaConnector;
private readonly Connector _generoConnector;
private readonly Connector _musicaConnector;
public Service1()
{
_usuarioConnector = new Connector("UsuarioBase");
_bandaConnector = new Connector("BandaBase");
_generoConnector = new Connector("GeneroBase");
_musicaConnector = new Connector("MusicaBase");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartDebug();
}
public void StartDebug()
{
_thread = new Thread(OnTime);
_thread.Name = "My Worker Thread";
_thread.Start();
}
protected override void OnStop()
{
}
protected void OnTime()
{
while (true)
{
EventLog.WriteEntry("Dentro do WHILE foi executado!");
_updater.Do(Connection, _usuarioConnector, _generoConnector, _bandaConnector, _musicaConnector);
EventLog.WriteEntry("Fim do while");
Thread.Sleep(Interval);
}
}
}
}
Updater.CS
using rdi_musica.core;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace rdi_server.service
{
class Updater
{
public void Do(string Connection,
Connector usuario,
Connector genero,
Connector banda,
Connector musica)
{
var usuarios = Loader.LoadUsuarios(usuario);
var generos = Loader.LoadGeneros(genero);
var bandas = Loader.LoadBandas(banda);
var musicas = Loader.LoadMusicas(musica);
using (var connection = new SqlConnection(Connection))
{
connection.Open();
foreach (var _usuario in usuarios)
{
DomainDAO.InsertUsuario(connection, _usuario);
}
foreach (var _genero in generos)
{
DomainDAO.InsertGenero(connection, _genero);
}
foreach (var _banda in bandas)
{
DomainDAO.InsertBanda(connection, _banda);
}
foreach (var _musica in musicas)
{
DomainDAO.InsertMusica(connection, _musica);
}
}
}
}
}
What's probably happening is you have an unhandled exception happening somewhere, which is breaking out of your while loop.
You can use the windows event log in combination with try-catch to log your errors, without breaking your infinite loop:
protected void OnTime()
{
while (true)
{
try
{
EventLog.WriteEntry("Dentro do WHILE foi executado!");
_updater.Do(Connection, _usuarioConnector, _generoConnector, _bandaConnector, _musicaConnector);
EventLog.WriteEntry("Fim do while");
}
catch (Exception ex)
{
this.EventLog.WriteEntry("ERROR: " + ex.GetType().ToString() + " : " + ex.Message + " : " + ex.StackTrace, EventLogEntryType.Error);
}
Thread.Sleep(Interval);
}
}
I wonder what is the best way.
If I need to pass a class to a class constructor why should I use a variable inside my class.
Example:
using Beckhoff.App.Ads.Core.Plc;
Class test()
{
private static IBAAdsServer AdsServer;
private static IBAAdsCncClient _cncClient;
public test(IBAAdsServer _adsServer) //constructor
{
try
{
AdsServer = _adsServer;
_cncClient = AdsServer.GetAdsClient<IBAAdsCncClient>("CNC");
_cncClient.Synchronize = true;
}
catch (Exception Except)
{ MessageBox.Show("Error ! " + Except.Message); }
}
Why can't I do:
using Beckhoff.App.Ads.Core.Plc;
Class test()
{
private static IBAAdsCncClient _cncClient;
public test(IBAAdsServer _adsServer) //constructor
{
try
{
_cncClient = _adsServer.GetAdsClient<IBAAdsCncClient>("CNC");
_cncClient.Synchronize = true;
}
catch (Exception Except)
{ MessageBox.Show("Error ! " + Except.Message); }
}
I would like to use _adsServer in a lot of class not connected, how can I do that properly?
Thanks for help.
Ok, here is like I do now.
using Beckhoff.App.Ads.Core.Plc;
Class test()
{
private static IBAAdsServer AdsServer;
private static IBAAdsCncClient _cncClient;
public test(IBAAdsServer _adsServer) //constructor
{
try
{
AdsServer = _adsServer;
_cncClient = AdsServer.GetAdsClient<IBAAdsCncClient>("CNC");
_cncClient.Synchronize = true;
Classtocall newClass = ClasstoCall(_cncClient);//Passing the argument directly
}
catch (Exception Except)
{ MessageBox.Show("Error ! " + Except.Message); }
}
I have a project and one of the main methods is returning null when it is pretty clear to see I have assigned a value to it.
Program.cs:
using System;
namespace Sahara
{
class Program
{
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Title = "Loading Sahara...";
Console.CursorVisible = false;
Sahara.Initialize();
while (true)
{
Console.ReadKey();
}
}
}
}
Sahara.cs:
namespace Sahara
{
class Sahara
{
private static SaharaServer server;
public static void Initialize()
{
server = new SaharaServer();
}
public static SaharaServer GetServer()
{
return server;
}
}
}
SaharaServer:
using Sahara.Core.Config;
using Sahara.Core.Logging;
using Sahara.Core.Server;
using System;
using System.Diagnostics;
namespace Sahara
{
class SaharaServer
{
private readonly ServerStatusUpdater serverStatusUpdater;
private readonly LogManager logManager;
private readonly ServerInformation serverInformation;
private readonly DateTime startedTime;
private readonly ConfigManager configManager;
public SaharaServer()
{
logManager = new LogManager();
serverInformation = new ServerInformation();
foreach (string consoleOutputString in serverInformation.ConsoleLogo)
{
Console.WriteLine(consoleOutputString);
}
logManager.Log("Loading " + serverInformation.ServerName + "...", LogType.Information);
Stopwatch stopwatch = Stopwatch.StartNew();
configManager = new ConfigManager("Extra/Other/config.ini");
startedTime = DateTime.Now;
serverStatusUpdater = new ServerStatusUpdater();
stopwatch.Stop();
logManager.Log("Finished Loading! [" + stopwatch.ElapsedMilliseconds + "ms]", LogType.Warning);
Console.ForegroundColor = ConsoleColor.Black;
}
public LogManager GetLogManager()
{
return logManager;
}
public ServerInformation GetServerInformation()
{
return serverInformation;
}
public DateTime StartedTime
{
get { return startedTime; }
}
public ConfigManager GetConfigManager()
{
return configManager;
}
public void Dispose()
{
try
{
serverStatusUpdater.Dispose();
}
catch (Exception exception)
{
if (logManager != null)
{
logManager.Log("Error in disposing SaharaServer: " + exception.Message, LogType.Error);
logManager.Log(exception.StackTrace, LogType.Error);
}
}
finally
{
Environment.Exit(0);
}
}
}
}
But why is GetServer() in Sahara.cs returning null!!?!?!?!?
You call the ConfigManager constructor from within the SaharaServer constructor, so the constructor has not yet completed to set the server field and thus GetServer will return null.
CODE UPDATED TO REFLECT ANSWER: SAME PROBLEM STILL OCCURS
This class is supposed to run all tasks in the list, sleep and then wake up and repeat the process infinitely. For some reason though, after the first sleep, the sleepThread.RunWorkerAsync() call gets called twice for some reason. I can obviously solve this by:
if (!sleepThread.IsBusy) { sleepThread.RunWorkerAsync(); }
but that feels like a work around.
Here is the main routine class:
public class ServiceRoutine
{
private static volatile ServiceRoutine instance;
private static object instanceLock = new object();
private static object listLock = new object();
private static readonly List<Task> taskList = new List<Task>()
{
new UpdateWaferQueueTask(),
new UpdateCommentsTask(),
new UpdateFromTestDataTask(),
new UpdateFromTestStationLogsTask(),
new UpdateFromWatchmanLogsTask(),
new UpdateStationsStatusTask()
};
private List<Task> runningTasks;
private BackgroundWorker sleepThread;
private Logger log;
private ServiceRoutine()
{
log = new Logger();
runningTasks = new List<Task>();
sleepThread = new BackgroundWorker();
sleepThread.WorkerReportsProgress = false;
sleepThread.WorkerSupportsCancellation = false;
sleepThread.DoWork += (sender, e) =>
{
int sleepTime = ConfigReader.Instance.GetSleepTime();
log.Log(Logger.LogType.Info,
"service sleeping for " + sleepTime / 1000 + " seconds");
Thread.Sleep(sleepTime);
};
sleepThread.RunWorkerCompleted += (sender, e) => { Run(); };
}
public static ServiceRoutine Instance
{
get
{
if (instance == null)
{
lock (instanceLock)
{
if (instance == null)
{
instance = new ServiceRoutine();
}
}
}
return instance;
}
}
public void Run()
{
foreach (Task task in taskList)
{
lock (listLock)
{
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
runningTasks.Remove(completedTask);
if (runningTasks.Count <= 0)
{
sleepThread.RunWorkerAsync();
}
};
task.Execute();
}
}
}
}
this is called like this:
ServiceRoutine.Instance.Run();
from the service start method. Here is the Task class as well:
public abstract class Task
{
private Logger log;
protected BackgroundWorker thread;
public delegate void TaskPointer(Task task);
public TaskPointer TaskComplete;
public Task()
{
log = new Logger();
thread = new BackgroundWorker();
thread.WorkerReportsProgress = false;
thread.DoWork += WorkLoad;
thread.RunWorkerCompleted += FinalizeTask;
}
protected abstract string Name { get; }
protected abstract void WorkLoad(object sender, DoWorkEventArgs e);
private string GetInnerMostException(Exception ex)
{
string innerMostExceptionMessage = string.Empty;
if (ex.InnerException == null) { innerMostExceptionMessage = ex.Message; }
else
{
while (ex.InnerException != null)
{
innerMostExceptionMessage = ex.InnerException.Message;
}
}
return innerMostExceptionMessage;
}
protected void FinalizeTask(object sender, RunWorkerCompletedEventArgs e)
{
try
{
if (e.Error != null)
{
string errorMessage = GetInnerMostException(e.Error);
log.Log(Logger.LogType.Error, this.Name + " failed: " + errorMessage);
}
else
{
log.Log(Logger.LogType.Info, "command complete: " + this.Name);
}
}
catch (Exception ex)
{
string errorMessage = GetInnerMostException(ex);
log.Log(Logger.LogType.Error, this.Name + " failed: " + errorMessage);
}
finally { TaskComplete(this); }
}
public void Execute()
{
log.Log(Logger.LogType.Info, "starting: " + this.Name);
thread.RunWorkerAsync();
}
}
The question is, why is sleepThread.RunWorkerAsync() getting called twice and is there a better way to get this work without checking if the thread is busy before calling it?
You are facing a race condition here. The problem is in the TaskComplete callback. Last two tasks remove themselves from the runningTasks list before executing the if condition. When it is executed, the list count is zero. You should lock the list before changing its. The lock needs to be taken in the TaskComplete callback:
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
lock (runningTasks)
{
runningTasks.Remove(completedTask);
if (runningTasks.Count <= 0)
{
sleepThread.RunWorkerAsync();
}
}
};
task.Execute();
SOLVED
I tried several different locking techniques on the runningTasks list but nothing worked. After changing runningTasks to a BlockingCollection, everything worked perfectly.
Here is the new add/remove implementation using a BlockingCollection instead of a List:
foreach (Task task in taskList)
{
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
runningTasks.TryTake(out completedTask);
if (runningTasks.Count <= 0 && completedTask != null)
{
sleepThread.RunWorkerAsync();
}
};
task.Execute();
}
I was experimenting with the new C# await feature. I made a custom awaiter implementation as follows:
using System;
using System.Runtime.CompilerServices;
using System.Threading;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
T1();
Console.WriteLine("After t1");
}
private static async void T1()
{
CustomAwaitable a = new Sleeper().Sleep();
object r = await a;
Console.WriteLine("sleeper awakes " + r);
}
}
internal class CustomAwaitable
{
private readonly Sleeper m_sleeper;
public CustomAwaitable(Sleeper s)
{
m_sleeper = s;
}
public MyAwaiter GetAwaiter()
{
return new MyAwaiter(m_sleeper);
}
}
internal class Sleeper
{
public ManualResetEvent Handle = new ManualResetEvent(false);
public bool Awake { get; set; }
public int Result
{
get { return Environment.TickCount; }
}
public CustomAwaitable Sleep()
{
new Thread(() =>
{
Thread.Sleep(5000);
Awake = true;
Handle.Set();
}).Start();
Console.WriteLine("begin sleeping " + Result);
return new CustomAwaitable(this);
}
}
internal class MyAwaiter : INotifyCompletion
{
private readonly Sleeper m_sleeper;
public MyAwaiter(Sleeper sleeper)
{
m_sleeper = sleeper;
}
public bool IsCompleted
{
get { return m_sleeper.Awake; }
}
public void OnCompleted(Action continuation)
{
// This works!!
//new Thread(() =>
//{
// m_sleeper.Handle.WaitOne();
// continuation();
//}).Start();
// This doesn't work!!
Action k = () =>
{
m_sleeper.Handle.WaitOne();
continuation();
};
k.BeginInvoke(null, null);
}
public object GetResult()
{
return m_sleeper.Result;
}
}
}
The problem is that, in the OnCompleted method, when I schedule the continuation code execution using BeginInvoke, the GetResult method is never called. But when I create a thread manually to do the same thing, everything works as expected. I know that BeginInvoke uses the thread pool internally, which should work the same way as the thread approach (I know that there is a thread count limit with thread pool, but it is negligible in this case as I am not running anything else).
What are your ideas? Thanks!