Thread.Suspend() is obsolete - c#

I have a problem with thread, I want to create n thread and write a log (with method write, already implemented)
This is an unit test, when I run it, it works nice, but an exception appears :
System.AppDomainUnloadedException: Attempted to access an unloaded AppDomain. This can happen if the test(s) started a thread but did not stop it. Make sure that all the threads started by the test(s) are stopped before completion.
So, I tried to use ThreadC.Suspend() and error disappears, but mehod Suspend is obsolete..
How can I fix it?
public void TestMethod1()
{
try
{
LogTest logTest = new LogTest(new FileLog());
logTest.PerformanceTest();
logTest = new LogTest(new CLogApi());
logTest.PerformanceTest();
logTest = new LogTest(new EmptyLog());
logTest.PerformanceTest();
}
catch (Exception)
{
Assert.IsTrue(false);
}
}
public class LogTest
{
private readonly Log log;
private int numberOfIterations = 5;
public LogTest(Log log)
{
this.log = log;
}
public void PerformanceTest()
{
for (int i = 0; i < this.numberOfIterations; i++)
{
try
{
Thread threadC = Thread.CurrentThread;
threadC = new Thread(this.ThreadProc);
threadC.Name = i.ToString();
threadC.Start();
// threadC.IsBackground = true;
}
catch (Exception)
{
Assert.IsTrue(false);
}
}
}
private void ThreadProc()
{
try
{
this.log.Write(" Thread : " + Thread.CurrentThread.Name.ToString());
this.log.Write(" Thread : " + Thread.CurrentThread.Name.ToString());
this.log.Write(" Thread : " + Thread.CurrentThread.Name.ToString());
this.log.Write(" Thread : " + Thread.CurrentThread.Name.ToString());
}
catch (Exception)
{
Assert.IsTrue(false);
}
}
}

1: You should use "Assert.Fail()" instead Assert.IsTrue(false);
2: Read the Microsoft documentation if you use an obsolete method. They write what you can use instead."Thread.Suspend has been deprecated. Please use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources."
3: If i understand you correctly you want to kill all running threads or wait for them. You can use "Thread.Join()" https://msdn.microsoft.com/de-de/library/95hbf2ta(v=vs.110).aspx
You can store all threads in an Array or list an join all threads at the end.
4: Instead using threads you can use the async pattern and wait for all Tasks with Task.WaitAll(tasks) https://msdn.microsoft.com/en-us/library/dd270695(v=vs.110).aspx

Related

How to get background logger class to finish logging when application exits. (C# multi-threading)

I am new to C# programming and just for learning's sake I wanted to make an asynchronous application logger that runs on a low priority background thread. I have written a logger class that serves as an interface for any other class in the application to make new log entries. This logger then simply sends it to a log dispatcher, which then pushes it to a BlockingCollection< Log >, from which a loop continuously tries to take a log from and write to the logfile on a background thread.
HOWEVER, The problem I am having is that if the application requests a log entry just before it exits, the logs are never written. The Dispose method of the LogDispatcher is also never called as the exit log in the method is never written. I am not sure how to make the background thread finish going through the entire blocking collection before it terminates and then call the dispose method when the parent application thread terminates. Here is the code.
public sealed class Logger : ILogger
{
// Fully lazy implementation for
// 1) learning purposes and
// 2) in case log disabling is a feature to be added in the future
private static readonly Lazy<Logger> L = new Lazy<Logger>(() => new Logger());
public static Logger Instance
{
get
{
return L.Value;
}
}
private double entryNumber = 0;
private int verbosity { get; set; }`private Logger()
{
this.verbosity = 3;
LogDispatcher.Instance.pushNewLog(new Log(
Log.LogType.Debug,
entryNumber++,
"LOG -- LogFile created with verbosity " + this.verbosity,
DateTime.Now.ToString("yyyy - mm - dd hh: mm:ss.fff")));
}
public void debug(string message)
{
if (this.verbosity > 2)
{
LogDispatcher.Instance.pushNewLog(new Log(
Log.LogType.Debug,
entryNumber++,
message,
DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"
)));
}
}
public void warning(string warning)
{
if (this.verbosity > 1)
{
LogDispatcher.Instance.pushNewLog(new Log(
Log.LogType.Warning,
entryNumber++,
warning,
DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"
)));
}
}
public void exception(string message, Exception e)
{
LogDispatcher.Instance.pushNewLog(new Log(
Log.LogType.Exception,
(entryNumber++),
message,
DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"),
Thread.CurrentThread.ManagedThreadId,
e
));
}
The code for the dispatcher is as follows
internal class LogDispatcher : IDisposable
{
private static readonly Lazy<LogDispatcher> LD = new Lazy<LogDispatcher>(() => new LogDispatcher());
private readonly StreamWriter LogFile;
private readonly BlockingCollection<Log> logQueue;
private Thread loggingThread;
private bool terminate = false;
public static LogDispatcher Instance
{
get
{
return LD.Value;
}
}private LogDispatcher()
{
// initialize the log folder
string logPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\NETLogger";
{
try
{
Directory.CreateDirectory(logPath);
}
catch (Exception e)
{
Console.WriteLine("An error occured while making the logfile.");
Console.WriteLine(e.ToString());
}
}
// now make logfile
try
{
this.LogFile = File.CreateText(logPath + "\\LogFile.txt");
this.LogFile.AutoFlush = true;
}
catch (Exception e)
{
Console.WriteLine("An error occured while opening LogFile.txt");
Console.WriteLine(e.ToString());
}
// make the blocking collection that stores all queued logs
this.logQueue = new BlockingCollection<Log>();
// initialize writer loggingThread to run in the background
this.loggingThread = new Thread(new ThreadStart(logWriter));
this.loggingThread.IsBackground = true;
this.loggingThread.Start();
}
public void logWriter()
{
Log writingLog = new Log();
while (!terminate && logQueue.Count != 0)
{
if (this.logQueue.TryTake(out writingLog, -1))
{
switch(writingLog.lType)
{
case (Log.LogType.Debug) :
LogFile.WriteLine(writingLog.entryNumber + " -- DEBUG -- " + writingLog.timeStamp);
LogFile.WriteLine("\t" + writingLog.message);
break;
case (Log.LogType.Warning) :
LogFile.WriteLine(writingLog.entryNumber + " -- WARNING -- " + writingLog.timeStamp);
LogFile.WriteLine("\t" + writingLog.message);
break;
case (Log.LogType.Exception) :
LogFile.WriteLine(writingLog.entryNumber + " -- EXCEPTION -- " + writingLog.timeStamp);
LogFile.WriteLine("\t ============== EXCEPTION INFORMATION FOLLOWS ============== ");
LogFile.WriteLine("\t Log Message : " + writingLog.message);
LogFile.WriteLine("\t Exception Message: " + writingLog.e.Message);
LogFile.WriteLine("\t Exception Thread :" + writingLog.threadId);
LogFile.WriteLine("\t Source: " + writingLog.e.ToString());
LogFile.WriteLine("\t=============== END EXCEPTION INFORMATION ================== ");
break;
}
}
}
}
public void pushNewLog(Log log)
{
logQueue.Add(log);
}
public void Dispose()
{
this.logQueue.Add(new Log(
Log.LogType.Debug,
-1,
"Terminating All Logging Procedures",
DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff")));
this.logQueue.CompleteAdding();
this.terminate = true;
this.loggingThread.Join();
}
~LogDispatcher()
{
this.Dispose();
}
Either use Thread.Join method or mark your thread as a foreground thread by setting IsBackground = false;.
From MSDN:
A thread is either a background thread or a foreground thread. Background threads are identical to foreground threads, except that background threads do not prevent a process from terminating. Once all foreground threads belonging to a process have terminated, the common language runtime ends the process. Any remaining background threads are stopped and do not complete.
I know you are probably learning threads but if that is not the case then use the higher abstraction so you do not have to deal with threads directly. Use Task like this:
Task task1 = Task.Factory.StartNew(() => DoSomething());
Task task2 = Task.Factory.StartNew(() => DoSomethingElse());
Task.WaitAll(task1, task2);
Console.WriteLine("All threads complete");
EDIT
In the comment the OP asked: why the dispose method is not called when the distructor for the dispatcher is called?
It is not called because you need to call it. See below pattern for how to do this.
public class ComplexResourceHolder : IDisposable
{
private IntPtr buffer; // unmanaged memory buffer
private SafeHandle resource; // disposable handle to a resource
public ComplexResourceHolder()
{
this.buffer = ... // allocates memory
this.resource = ... // allocates the resource
}
// disposing will be false when it is called from the finalize.
// I remember this by telling myself: "finalize has 'f' in it
// and false has 'f' in it so disposing is false when called by finalizer".
protected virtual void Dispose(bool disposing)
{
ReleaseBuffer(buffer); // release unmanaged memory
if (disposing)
{ // release other disposable objects
if (resource != null) resource.Dispose();
}
}
~ComplexResourceHolder()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
X AVOID making types finalizable.
Carefully consider any case in which you think a finalizer is needed. There is a real cost associated with instances with finalizers, from both a performance and code complexity standpoint. Prefer using resource wrappers such as SafeHandle to encapsulate unmanaged resources where possible, in which case a finalizer becomes unnecessary because the wrapper is responsible for its own resource cleanup.
X DO NOT make value types finalizable.
Only reference types actually get finalized by the CLR, and thus any attempt to place a finalizer on a value type will be ignored. The C# and C++ compilers enforce this rule.
✓ DO make a type finalizable if the type is responsible for releasing an unmanaged resource that does not have its own finalizer.

C# how cancel an executing method

I have a delegate method to run a heavy process in my app (I must use MS Framework 3.5):
private delegate void delRunJob(string strBox, string strJob);
Execution:
private void run()
{
string strBox = "G4P";
string strJob = "Test";
delRunJob delegateRunJob = new delRunJob(runJobThread);
delegateRunJob.Invoke(strBox, strJob);
}
In some part of the method runJobThread
I call to an external program (SAP - Remote Function Calls) to retrieve data. The execution of that line can take 1-30 mins.
private void runJobThread(string strBox, string strJob)
{
// CODE ...
sapLocFunction.Call(); // When this line is running I cannot cancel the process
// CODE ...
}
I want to allow the user cancel whole process.
How can achieve this? I tried some methods; but I fall in the same point; when this specific line is running I cannot stop the process.
Instead of using the delegate mechanism you have to study the async and await mechanism. When you understand this mechanism you can move to cancellationtoken.
An example doing both things can be found here :
http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx
Well; I find out a complicated, but effective, way to solve my problem:
a.) I created a "Helper application" to show a notification icon when the process is running (To ensure to don't interfere with the normal execution of the main app):
private void callHelper(bool blnClose = false)
{
if (blnClose)
fw.processKill("SDM Helper");
else
Process.Start(fw.appGetPath + "SDM Helper.exe");
}
b.) I created a Thread that call only the heavy process line.
c.) While the Thread is alive I check for external file named "cancel" (The "Helper application" do that; when the user click an option to cancel the process the Helper create the file).
d.) If exists the file; dispose all objects and break the while cycle.
e.) The method sapLocFunction.Call() will raise an exception but I expect errors.
private void runJobThread(string strBox, string strJob)
{
// CODE ...
Thread thrSapCall = new Thread(() =>
{
try { sapLocFunction.Call(); }
catch { /* Do nothing */ }
});
thrSapCall.Start();
while (thrSapCall.IsAlive)
{
Thread.Sleep(1000);
try
{
if (fw.fileExists(fw.appGetPath + "\\cancel"))
{
sapLocFunction = null;
sapLocTable = null;
sapConn.Logoff();
sapConn = null;
canceled = true;
break;
}
}
finally { /* Do nothing */ }
}
thrSapCall = null;
// CODE ...
}
Works like a charm!
I think you would have to resort to the method described here. Read the post to see why this is a long way from ideal.
Perhaps this might work...
private void runJobThread(string strBox, string strJob, CancellationToken token)
{
Thread t = Thread.CurrentThread;
using (token.Register(t.Abort))
{
// CODE ...
sapLocFunction.Call(); // When this line is running I cannot cancel the process
// CODE ...
}
}
A bit of dnspy exposes a cancel method on nco3.0.
private readonly static Type RfcConnection = typeof(RfcSessionManager).Assembly.GetType("SAP.Middleware.Connector.RfcConnection");
private readonly static Func<RfcDestination, object> GetConnection = typeof(RfcSessionManager).GetMethod("GetConnection", BindingFlags.Static | BindingFlags.NonPublic).CreateDelegate(typeof(Func<RfcDestination, object>)) as Func<RfcDestination, object>;
private readonly static MethodInfo Cancel = RfcConnection.GetMethod("Cancel", BindingFlags.Instance | BindingFlags.NonPublic);
object connection = null;
var completed = true;
using (var task = Task.Run(() => { connection = GetConnection(destination); rfcFunction.Invoke(destination); }))
{
try
{
completed = task.Wait(TimeSpan.FromSeconds(invokeTimeout));
if (!completed)
Cancel.Invoke(connection, null);
task.Wait();
}
catch(AggregateException e)
{
if (e.InnerException is RfcCommunicationCanceledException && !completed)
throw new TimeoutException($"SAP FM {functionName} on {destination} did not respond in {timeout} seconds.");
throw;
}
}

C# Enqueue Failure

I have a simple logging mechanism that should be thread safe. It works most of the time, but every now and then I get an exception on this line, "_logQ.Enqueue(s);" that the queue is not long enough. Looking in the debugger there are sometimes just hundreds of items, so I can't see it being resources. The queue is supposed to expand as needed. If I catch the exception as opposed to letting the debugger pause at the exception I see the same error. Is there something not thread safe here? I don't even know how to start debugging this.
static void ProcessLogQ(object state)
{
try
{
while (_logQ.Count > 0)
{
var s = _logQ.Dequeue();
string dir="";
Type t=Type.GetType("Mono.Runtime");
if (t!=null)
{
dir ="/var/log";
}else
{
dir = #"c:\log";
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
}
if (Directory.Exists(dir))
{
File.AppendAllText(Path.Combine(dir, "admin.log"), DateTime.Now.ToString("hh:mm:ss ") + s + Environment.NewLine);
}
}
}
catch (Exception)
{
}
finally
{
_isProcessingLogQ = false;
}
}
public static void Log(string s) {
if (_logQ == null)
_logQ = new Queue<string> { };
lock (_logQ)
_logQ.Enqueue(s);
if (!_isProcessingLogQ) {
_isProcessingLogQ = true;
ThreadPool.QueueUserWorkItem(ProcessLogQ);
}
}
Note that the threads all call Log(string s). ProcessLogQ is private to the logger class.
* Edit *
I made a mistake in not mentioning that this is in a .NET 3.5 environment, therefore I can't use Task or ConcurrentQueue. I am working on fixes for the current example within .NET 3.5 constraints.
** Edit *
I believe I have a thread-safe version for .NET 3.5 listed below. I start the logger thread once from a single thread at program start, so there is only one thread running to log to the file (t is a static Thread):
static void ProcessLogQ()
{
while (true) {
try {
lock (_logQ);
while (_logQ.Count > 0) {
var s = _logQ.Dequeue ();
string dir = "../../log";
if (!Directory.Exists (dir))
Directory.CreateDirectory (dir);
if (Directory.Exists (dir)) {
File.AppendAllText (Path.Combine (dir, "s3ol.log"), DateTime.Now.ToString ("hh:mm:ss ") + s + Environment.NewLine);
}
}
} catch (Exception ex) {
Console.WriteLine (ex.Message);
} finally {
}
Thread.Sleep (1000);
}
}
public static void startLogger(){
lock (t) {
if (t.ThreadState != ThreadState.Running)
t.Start ();
}
}
private static void multiThreadLog(string msg){
lock (_logQ)
_logQ.Enqueue(msg);
}
Look at the TaskParallel Library. All the hard work is already done for you. If you're doing this to learn about multithreading read up on locking techniques and pros and cons of each.
Further, you're checking if _logQ is null outside your lock statement, from what I can deduce it's a static field that you're not initializing inside a static constructor. You can avoid doing this null check (which should be inside a lock, it's critical code!) you can ensure thread-safety by making it a static readonly and initializing it inside the static constructor.
Further, you're not properly handling queue states. Since there's no lock during the check of the queue count it could vary on every iteration. You're missing a lock as your dequeuing items.
Excellent resource:
http://www.yoda.arachsys.com/csharp/threads/
For a thread-safe queue, you should use the ConcurrentQueue instead:
https://msdn.microsoft.com/en-us/library/dd267265(v=vs.110).aspx

Process is terminated due to StackOverflowException

This is difficult situation to explain. Have a service process that starts 2 threads, each thread loops forever but sleeps for 5 minutes each once the payload is finished.
Problem is that my second thread terminates well before the payload is even finished, for no apparent reason, and i also can't catch the exception as it seems to be triggered from outside the delegate process?
Any suggestions on how to find the problem?
The code....
public void StartService()
{
ThreadStart stRecieve = new ThreadStart(DownloadNewMail);
ThreadStart stSend = new ThreadStart(SendNewMail);
senderThread = new Thread(stRecieve);
recieverThread = new Thread(stSend);
sendStarted = true;
recieveStarted = true;
senderThread.Start();
recieverThread.Start();
}
private void DownloadNewMail()
{
while(recieveStarted)
{
//Payload....
if (recieveStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
private void SendNewMail()
{
while(sendStarted)
{
//Payload....
if (sendStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
Try to check callstack lenght in your code:
class Program
{
static void Main(string[] args)
{
try
{
Hop();
}
catch (Exception e)
{
Console.WriteLine("Exception - {0}", e);
}
}
static void Hop()
{
CheckStackTrace();
Hip();
}
static void Hip()
{
CheckStackTrace();
Hop();
}
static void CheckStackTrace()
{
StackTrace s = new StackTrace();
if (s.FrameCount > 50)
throw new Exception("Big stack!!!!");
}
}
If you are having trouble following the flow of your application's code execution, try logging the entrance of methods with a timestamp and threadid.
Also, You can't catch the exception because it is a StackOverflowException.
See msdn: "Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. "
Do you utlize any heavy-weight library for tasks like DownloadNewMail and SendNewMail? For example I encountered StackOverflows when running large jobs using Microsoft.SqlServer.Dts.Runtime.Package. Try running the same workload sequentially inside a command-line application to see if the issue persists.

Exception handling in threads

Recently i have attended an interview . A code snippet is given to me.I know,the interviewer took it from albhari's threading sample.
public static void Main()
{
try
{
new Thread (Go).Start();
}
catch (Exception ex)
{
// We'll never get here!
Console.WriteLine ("Exception!");
}
}
static void Go() { throw null; }
The modification of the above code as
public static void Main()
{
new Thread (Go).Start();
}
static void Go()
{
try
{
...
throw null; // this exception will get caught below
...
}
catch (Exception ex)
{
Typically log the exception, and/or signal another thread
that we've come unstuck
...
}
}
would be the good candidate to handle the exception.
I have been asked, "Except the above trail what are the other alternatives would fit as good solution?. It was hard to find the alternative,so i raise it here to gather your suggestion.
Exception thrown in a thread normally couldn't be caught in another thread.
You'd better to catch it in function Go and pass it to main thread explicitly.
However, if you just want to log all unhandled messages from all threads, you may use AppDomain.UnhandledException event or equivalent events at Application class if you are developing WinForms or WPF app.
what are the other alternatives would fit as good solution?.
Solution to what? What problem are you trying to solve?
If you use BackgroundWorker, as opposed to Thread, it has an RunWorkerCompleted event, and within that you can check the RunWorkerCompletedEventArgs param for the Error property. This generally is used in WinForms or WPF apps, because there is good support for BackgroundWorker in the Visual Studio designer.
You could also define a delegate for Go(), and call BeginInvoke() on it. Of course you need the EndInvoke() too.
Also, it's generally not a good idea to start up random threads. ThreadPool.QueueUserWorkItem, BackgroundWorker, or asynch delegates all use the ThreadPool, and are recommended.
There are alternatives listed on Joe Albahari's website:
http://www.albahari.com/threading/#_Exception_Handling
"There are, however, some cases where you don’t need to handle exceptions on a worker thread, because the .NET Framework does it for you. These are covered in upcoming sections, and are:
-Asynchronous delegates
-BackgroundWorker
-The Task Parallel Library (conditions apply)"
You can use the AppDomain.UnhandledException event
I think this is the easiest way is:
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler((object sender2, DoWorkEventArgs e2) =>
{
throw new Exception("something bad");
e2.Result = 1 + 1;
});
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((object sender2, RunWorkerCompletedEventArgs e2) =>
{
if (e2.Error != null)
{
Console.WriteLine("Error: " + e2.Error.Message);
}
});
bw.RunWorkerAsync();
but there is another way that some might prefer if you want to synchronize the thread (perhaps this is on a thread other than the GUI thread):
private class FileCopier
{
public bool failed = false;
public Exception ex = null;
public string localPath;
public string dstPath;
public FileCopier(string localPath, string dstPath)
{
this.localPath = localPath;
this.dstPath = dstPath;
}
public void Copy()
{
try{
throw new Exception("bad path");
}catch(Exception ex2)
{
ex = ex2;
failed = true;
}
}
}
public static void Main()
{
FileCopier fc = new FileCopier("some path", "some path");
Thread t = new Thread(fc.Copy);
t.Start();
t.Join();
if (fc.failed)
Console.WriteLine(fc.ex.Message);
}
Note that the second example would make more sense if you have several threads and you loop through them and join all...but I kept the example simple.
the 3rd pattern would be using Task Factory which is cleaner:
private static test(){
List<Task<float>> tasks = new List<Task<float>>();
for (float i = -3.0f; i <= 3.0f; i+=1.0f)
{
float num = i;
Console.WriteLine("sent " + i);
Task<float> task = Task.Factory.StartNew<float>(() => Div(5.0f, num));
tasks.Add(task);
}
foreach(Task<float> t in tasks)
{
try
{
t.Wait();
if (t.IsFaulted)
{
Console.WriteLine("Something went wrong: " + t.Exception.Message);
}
else
{
Console.WriteLine("result: " + t.Result);
}
}catch(Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
}
}
private static float Div(float a, float b)
{
Console.WriteLine("got " + b);
if (b == 0) throw new Exception("Divide by zero");
return a / b;
}

Categories

Resources