lock statement not working when there is a loop inside it? - c#

See this code:
public class multiply
{
public Thread myThread;
public int Counter
{
get;
private set;
}
public string name
{
get;
private set;
}
public void RunConsolePrint()
{
lock(this)
{
RunLockCode("lock");
}
}
private void RunLockCode(string lockCode)
{
Console.WriteLine("Now thread "+lockCode+" " + name + " has started");
for (int i = 1; i <= Counter; i++)
{
Console.WriteLine(lockCode+" "+name + ": count has reached " + i + ": total count is " + Counter);
}
Console.WriteLine("Thread " + lockCode + " " + name + " has finished");
}
public multiply(string pname, int pCounter)
{
name = pname;
Counter = pCounter;
myThread = new Thread(new ThreadStart(RunConsolePrint));
}
}
And this is the test run code:
static void Main(string[] args)
{
int counter = 50;
multiply m2 = new multiply("Second", counter);
multiply m1 = new multiply("First", counter);
m1.myThread.Start();
m2.myThread.Start();
Console.ReadLine();
}
I would expect that m2 must execute from start to finish before m1 starts executing, or vice versa, because of the lock statement. But the result I found was the call to lock first and lock second was intermingled together, i.e., something like this
Now thread lock First has started
Now thread lock Second has started
lock First: Count has reached 1: total count is 50
lock First: Count has reached 2: total count is 50
lock Second: Count has reached 1: total count is 50
What did I do wrong?

Each instance of the code is locking on a different object. Your lock object needs to be shared between all instances -- make it a static class variable.
private static object syncRoot = new object();
public void RunConsolePrint()
{
lock(syncRoot)
{
RunLockCode("lock");
}
}

Related

Multithreads - passing arguments and receiving results

I am trying various options on working with threads. I wrote the code below, but it does not work as expected. How can I fix the code, so that the main function will correctly display the product?
using System;
using System.Threading;
namespace MultiThreads
{
class Program
{
static int prod;
public static void Main(string[] args)
{
Thread thread = new Thread(() => Multiply(2, 3));
thread.Start();
for(int i = 0; i < 10; i++) { // do some other work until thread completes
Console.Write(i + " ");
Thread.Sleep(100);
}
Console.WriteLine();
Console.WriteLine("Prod = " + prod); // I expect 6 and it shows 0
Console.ReadKey(true);
}
public static void Multiply(int a, int b)
{
Thread.Sleep(2000);
prod = a * b;
}
}
}
Ignoring the fact that you should be using non-blocking tasks, volatile properties and other coroutine principals, the immediate reason your program does not work as intended is because you didn't re-join the child thread back into the parent. See Join
Without the join, the Console.WriteLine("Prod = " + prod); occurs before the assignment prod = a * b;
static int prod;
static void Main(string[] args)
{
Thread thread = new Thread(() => Multiply(2, 3));
thread.Start();
for (int i = 0; i < 10; i++)
{ // do some other work until thread completes
Console.Write(i + " ");
Thread.Sleep(100);
}
thread.Join(); // Halt current thread until the other one finishes.
Console.WriteLine();
Console.WriteLine("Prod = " + prod); // I expect 6 and it shows 0
Console.ReadKey(true);
}
public static void Multiply(int a, int b)
{
Thread.Sleep(2000);
prod = a * b;
}

how to use text based console progress bar in multithreading C#

Hi I have a program that downloads + extracts the files in parallel (in threads).
it is a console app,and I want to show the Progress Bar for each operation in each thread.
for eg:
File 1 [==========35% ] 35mb of 100mb downloaded
File 2 [====20% ] 20mb of 100mb downloaded
File1 Downloaded,
File 1 [=============50% ] 50% extracted.
and so on.
note: I am able to show the console outputs as Code below, but would like to use this Progress Bar in my Console APP.
How can I use solution proposed in https://gist.github.com/DanielSWolf/0ab6a96899cc5377bf54 in this case ?
public static void DownloadAndGetFiles()
{
try
{
Parallel.ForEach(FileIds, currentId =>
{
int currentId = FileIds.Id
clientFileDownload(currentId);
});
}
catch (Exception e)
{
}
}
private static void clientFileDownload(int currentId)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
string downloadedFile = #"d:\tmp\";
client.DownloadFileAsync(new Uri(currentId.URL), downloadedFile); //some URL
while (client.IsBusy) { }
string temp = ExtractAndRename(currentId);
}
private static void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
//Prints: "Downloaded 3mb of 61.46mb (4%)"
Console.WriteLine("Downloaded "
+ ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " of "
+ ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " (" + e.ProgressPercentage + "%)");
}
private static string ExtractAndRename(int currentId)
{
//using SevenZipExtractor lib http://stackoverflow.com/questions/20898794/how-to-extract-files-in-my-archive-one-by-one-using-sevenzipsharp
SevenZipExtractor extractor = new SevenZipExtractor(#"d:\tmp\" + id.Name);
extractor.Extracting += extractor_Extracting;
extractor.ExtractArchive(#"d:\tmp\" + extractName[0]);
return (#"d:\tmp\" + extractName[0]);
}
public static void extractor_Extracting(object sender, SevenZip.ProgressEventArgs p)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("\b\b{0}% Extracted", p.PercentDone);
Console.ResetColor();
}
Provide every thread with a variable y which contains the line number it is allowed to write to.
Before a thread wants to update the screen, create a lock. The console can be used by only one thread at a time. Otherwise results of several threads will mix up.
Move the cursor to line specified by y and update that line.
Release the lock.
An example:
static private readonly object _sync = new object();
private static void UpdateProgress(int y, string item, int progress, int total)
{
int percentage = (int)100.0 * progress / total;
lock(_sync)
{
Console.CursorLeft = 0;
Console.CursorTop = y;
Console.Write(item + " [" + new string('=', percentage / 2) + "] " + percentage + "%");
}
}
You can call this method from your method clientFileDownload, which has to be modified a bit:
private static void clientFileDownload(int currentId, int y)
and should be called when creating the threads like this:
int y = 0;
Parallel.ForEach(FileIds, currentId =>
{
int currentId = FileIds.Id
clientFileDownload(currentId, y);
Interlocked.Increment(ref y);
});

c# 2 events with same nameļ¼Œ got chaos at running time, how should i avoid this?

I have a method "Add2List", who creates a ManualResetEvent and stores it in SortedList of a instance, then waits for signaling, then do some work and dispose the event.
I have another method "DoSomething", who listens to remote server and then signals the stored manual events according to Guid.
in the multithreading context, multi threads calls method "Add2List", so in the sortedlist there may have several manual event with same name at the same moment. But this may cause chaos. How should i avoid this?
To be simpler, i wrote this test code:
Class Program
{
static void Main(string[] args)
{
StringBuilder str = new StringBuilder();//a string to record what happened
//test iteratively
for(int i=0;i<100;i++)
{
EventHolder holder = new EventHolder();
Signaler ob2 = new Signaler();
Thread th1 = new Thread(holder.Add2List);
Thread th2 = new Thread(holder.Add2List);
Thread th3 = new Thread(ob2.DoSomething);
th1.Start(1);
th2.Start(2);
th3.Start();
//Make sure all thread is ended before the next iteration.
while(th1.IsAlive){ Thread.Sleep(200); }
while(th2.IsAlive){ Thread.Sleep(200); }
while(th3.IsAlive){ Thread.Sleep(200); }
}
Console.Read();
}
public class EventHolder
{
static SortedList<int, ManualResetEvent> MyManualEventList = new SortedList<int, ManualResetEvent>();
public EventHolder()
{
MyManualEventList = new SortedList<int, ManualResetEvent>();
Signaler.SignalMyManualEvent += OnSignalMyManualEvent;
}
void OnSignalMyManualEvent(int listindex)
{
try { MyManualEventList[listindex].Set(); }
catch(Exception e)
{
Console.WriteLine("Exception throws at " + System.DateTime.Now.ToString() +" Exception Message:"
Console.WriteLine(e.Message);
int temp = 0; //*Here is a breakpoint! To watch local variables when exception happens.
}
}
public void Add2List(object listindex)
{
ManualResetEvent MyManualEvent = new ManualResetEvent(false);
MyManualEvent.Reset();
MyManualEventList.Add((int)listindex, eve);
//in this test, this countdownevent need to be signaled twice, for it has to wait until all 2 event been added to MyManualEventList
Signaler.StartTrySignal.Signal();
MyManualEvent.WaitOne();
Console.WriteLine("Event" + ((int)listindex).ToString() + " been detected at " + System.DateTime.Now.Tostring());
MyManualEvent.Dispose();
}
}
public class Signaler
{
public delegate void Signalhandler(int listindex);
public static event Signalhandler SignalMyManualEvent;
public static CountDownEvent StartTrySignal = new CountDownEvent(2); // signaled twice so that the 2 manual events were added to sortedlist
void RaiseSignalMyManualEvent(int listindex)
{
var vr = SignalMyManualEvent;
if(vr != null)
vr(listindex);
}
int i = 0, j = 0, k = 0;
// here i use 2 prime numbers to simulate the happening of 2 random events
public Signaler()
{
StartTrySignal.Reset();
}
public void DoSomething()
{
StartTrySignal.Wait(); // wait for the 2 manual events been added to sortedlist
//To signal MyManualEventList[1] or MyManualEventList[2]
while(i + j == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 613 == 0) { i = 1; Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(1); }
else if(k % 617 == 0) { j = 1; Console.WriteLine("Event1 Raised!"; RaiseSignalMyManualEvent(2); }
}
//if MyManualEventList[1] has not been signaled, wait something to happen, and signal it.
while(i == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 613 == 0)
{
i = 1;
if(j>0)
{
m++;
Console.WriteLine("All 2 Events Raised! - iteration " + m.ToString());
}
RaiseSignalMyManualEvent(1);
}
}
//if MyManualEventList[2] has not been signaled, wait something to happen, and signal it.
while(j == 0)
{
Random rnd = new Random();
k = rnd.Next();
if(k % 617 == 0)
{
j = 1;
m++;
Console.WriteLine("All 2 Events Raised! - iteration " + m.ToString());
RaiseSignalMyManualEvent(2);
}
}
}
}
public class Counter //Provide a number to record iteration
{
public static int m = 0;
}
}
Result:
Sorry for do not have enough reputation to post images.
At the line where there's a breakpoint, system throws exception " the given key is not in dictionary". this exception happens randomly, sometimes because th1 disposed <2, MyManualEvent> or th2 disposed <1, MyManualEvent> , sometimes none has been disposed but it just cannot find anyone.
I run this program 3 times, exception happens at iteration12, iteration45, and iteration0 (at the beginning).
OK 2 answers
1: Your code returns "Event 1" after "All events", because the two console.writelines are in a race condition (the last while loop is never iterated)
2: the 'System' distingushes between the two ManualResetEvent objects becuase it references the SortedList you put them in. ie.
static SortedList<int, ManualResetEvent> MyManualEventList
= new SortedList<int, ManualResetEvent>();
public EventHolder() { Signaler.SignalMyManualEvent
+= OnSignalMyManualEvent; }
void OnSignalMyManualEvent(int listindex)
{
MyManualEventList[listindex].Set();
}
when you raise event 1 you call set on Item 1 in the SortedList and when you raise Event 2 you call set on Item 2 in the list.
this is bad because the calling code has no idea which thread it is allowing to continue and you could well get a null exception

Thread synchronization printing strings

I wrote a small programm which prints "x", then "+", then again "x" and so on.
The idea was to make it run in two threads so that the first thread prints "x" and the second prints "+". The output looks like this:
"x" -> Thread number 1
"+" -> Thread number 2
"x" -> Thread number 1enter code here
"+" -> Thread number 2
and so on..
What I wrote seems to work fine but it seems to me it is written in
very old-fashioned way:
public class Example
{
private static int count = 10;
private static int i = 0;
private static bool isOneActive = false;
private static void Run1(object o)
{
string s = o as string;
while(true)
{
if (!isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = true;
if (i++ > count) break;
}
}
}
private static void Run2(object o)
{
string s = o as string;
while(true)
{
if (isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = false;
if (i++ > count) break;
}
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
I know that now .NET has a lot of instruments for thread synchronization as for example ManualResetEvent class and Task library. So how could we write the same programm using ManualResetEvent class? Is it possible at all?
Your code isn't only old fashioned, it is very inefficient. It spins for no reason doing nothing but waiting; this is called Busy wait should be avoided whenever possible.
Better approach is to use Waithandles as noted in comments.
A naive implementation with very little change in your code will look something like the following.
public class Example
{
private static int count = 10;
private static int i = 0;
private static AutoResetEvent firstEvent = new AutoResetEvent(true);
private static AutoResetEvent secondEvent = new AutoResetEvent(false);
private static void Run1(object o)
{
string s = o as string;
while (true)
{
firstEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
secondEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
private static void Run2(object o)
{
string s = o as string;
while (true)
{
secondEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
firstEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
}
Note that firstEvent is instantiated with the initialState flag set to true which means that first thread doesn't waits initially.
Consider this example (fiddle):
static void Main(string[] args)
{
var console = new object();
int i = 0;
Task.Run(() =>
{
lock (console)
while (i++ < 10)
{
Console.Write(i);
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Task.Run(() =>
{
lock (console)
while (i < 10)
{
Console.Write('+');
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Console.ReadLine(); // Task.WaitAll might be better, remove for fiddle
}

C# Only One Thread Executes

I have a multithread application. I want only one thread to execute my function and other threads to pass it while my function executing. How can I do this?
My method is something like:
public void setOutput(int value)
{
try
{
GPOs gpos = reader.Config.GPO;
gpos[1].PortState = GPOs.GPO_PORT_STATE.TRUE;
gpos[2].PortState = GPOs.GPO_PORT_STATE.TRUE;
Thread.Sleep(WAIT);
gpos[1].PortState = GPOs.GPO_PORT_STATE.FALSE;
gpos[2].PortState = GPOs.GPO_PORT_STATE.FALSE;
}
catch (Exception ex)
{
logger.Error("An Exception occure while setting GPO to " + value + " " + ex.Message);
}
}
You can use a lock object in combination with Monitor.TryEnter.
private Object outputLock = new Object();
public void setOutput(int value)
{
if Monitor.TryEnter(outputLock)
{
try
{
.... your code in here
}
finally
{
Monitor.Exit(outputLock);
}
}
}
Only one thread at at time will be allowed into the Monitor.TryEnter block. If a thread arrives here while another thread is inside, then Monitor.TryEnter returns false.
You can use a Mutex
using System;
using System.Threading;
class Test
{
// Create a new Mutex. The creating thread does not own the
// Mutex.
private static Mutex mut = new Mutex();
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
{
// Create the threads that will use the protected resource.
for(int i = 0; i < numThreads; i++)
{
Thread myThread = new Thread(new ThreadStart(MyThreadProc));
myThread.Name = String.Format("Thread{0}", i + 1);
myThread.Start();
}
// The main thread exits, but the application continues to
// run until all foreground threads have exited.
}
private static void MyThreadProc()
{
for(int i = 0; i < numIterations; i++)
{
UseResource();
}
}
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
mut.WaitOne();
Console.WriteLine("{0} has entered the protected area",
Thread.CurrentThread.Name);
// Place code to access non-reentrant resources here.
// Simulate some work.
Thread.Sleep(500);
Console.WriteLine("{0} is leaving the protected area\r\n",
Thread.CurrentThread.Name);
// Release the Mutex.
mut.ReleaseMutex();
}
}
the accepted answer (https://stackoverflow.com/a/10753349/1606741 as of writing) is right, but I think using https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement is clearer and does basically the same.
One thread at a time can execute the block
private object once = new object();
public void setOutput(int value)
{
lock (once)
{
try
{
GPOs gpos = reader.Config.GPO;
gpos[1].PortState = GPOs.GPO_PORT_STATE.TRUE;
gpos[2].PortState = GPOs.GPO_PORT_STATE.TRUE;
Thread.Sleep(WAIT);
gpos[1].PortState = GPOs.GPO_PORT_STATE.FALSE;
gpos[2].PortState = GPOs.GPO_PORT_STATE.FALSE;
}
catch (Exception ex)
{
logger.Error("An Exception occure while setting GPO to " + value + " " + ex.Message);
}
}
}
You can give a name to your threads and check the name in the method
What about this solution:
private AutoResetEvent are = new AutoResetEvent();
public void setOutput(int value)
{
// Do not wait (block) == wait 0ms
if(are.WaitOne(0))
{
try
{
// Put your code here
}
finally
{
are.Set()
}
}
}
It seems be easier (cheaper) than Monitor with lock object, but maybe not so clear.

Categories