I've made this producer-consumer sample, but I don't know why it freezes at the end.
Where is the problem? If I put a breakpoint at line setNum(-99); and then after break continue it finishes OK.
Please also tell me if this code is ok and threadsafe. It must work like that, so meanwhile consumer is processing its given value, all other values from producer must be ignored.
I am very new to multithreading.
class Program
{
delegate void SetNumberDelegate(int number);
static void Main(string[] args)
{
Random rnd = new Random();
ConsumerClass consumerClass = new ConsumerClass();
SetNumberDelegate setNum = new SetNumberDelegate(consumerClass.setNumber);
Thread.Sleep(20);
int num;
int count = 0;
Console.WriteLine("Start");
while (count++ < 100)
{
num = rnd.Next(0, 100);
Console.WriteLine("Generated number {0}", num);
if (num > 30)
{
setNum(num);
}
}
setNum(-99);
Console.WriteLine("End");
Console.ReadKey();
}
}
class ConsumerClass : IDisposable
{
private int number;
private object locker = new object();
private EventWaitHandle _wh = new AutoResetEvent(false);
private Thread _consumerThread;
public ConsumerClass()
{
number = -1;
_consumerThread = new Thread(consumeNumbers);
_consumerThread.Start();
}
public void Dispose()
{
setNumber(-99);
_consumerThread.Join();
_wh.Close();
}
public void setNumber(int num)
{
if (Monitor.TryEnter(locker))
{
try
{
number = num;
Console.WriteLine("Setting number {0}", number);
}
finally
{
// Ensure that the lock is released.
Monitor.Exit(locker);
}
_wh.Set();
}
}
public void consumeNumbers()
{
while (true)
{
Monitor.Enter(locker);
if (number > -1)
{
try
{
Console.WriteLine("Processing number:{0}", number);
// simulate some work with number e.g. computing and storing to db
Thread.Sleep(20);
Console.WriteLine("Done");
number = -1;
}
finally
{
Monitor.Exit(locker);
}
}
else
{
if (number == -99)
{
Console.WriteLine("Consumer thread exit");
return;
}
Monitor.Exit(locker);
_wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
}
Rewrite setNumber like this to see your problem:
public void setNumber(int num) {
if (Monitor.TryEnter(locker)) {
// etc..
}
else Console.WriteLine("Number {0} will never make it to the consumer", num);
}
You'll have to block, waiting for the consumer to be ready to consume or use a queue.
Monitor.TryEnter(locker); will usually fail (including for -99) so you aren't going to set a fair number of the values, which is why the output is lacking in setting statements. This is because it will not wait to acquire the lock it will just return false.
The problem appears to be in the last part of the code. You're holding the lock when you execute this:
else
{
if (number == -99)
{
Console.WriteLine("Consumer thread exit");
return;
}
Monitor.Exit(locker);
_wh.WaitOne(); // No more tasks - wait for a signal
}
So if number == 99, the method returns without releasing the lock.
Your ConsumeNumbers method is overly complex. You can simplify it:
while (true)
{
_wh.WaitOne();
lock (locker)
{
if (number == -99)
break;
if (number > -1)
{
// process the number.
number = -1;
}
}
}
That will do the same thing, and is much simpler code.
By the way, the construct:
lock (locker)
{
// do stuff here
}
is the same as:
Monitor.Enter(locker);
try
{
// do stuff here
}
finally
{
Monitor.Exit(locker);
}
Related
I am trying to splice the work on multiple threads using ThreadPooling. I wanna use every available thread to assign (and calculate in a different part of the program down the line) the output of an array member to another array members.
It does work, but it is much slower than just adding them on a single thread. Is my usage wrong or is this operation too simple for multithreading?
arrayI and arrayX variables are in classScope, i couldnt pass them as QueueUserWorkItem argument without converting them in setNeuronInput.
if (layerType != 0)
{
for (arrayI = 0; arrayI < layerSize -1 ; arrayI++)
{
for (arrayX = 0; arrayX < network.Layers[layerIndex - 1].layerSize - 1; arrayX++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(setNeuronInput), null);
//Neurons[i].input[x] = _network.Layers[layerIndex - 1].Neurons[x].output;
}
}
}
//ThreadPool.GetAvailableThreads(out availableThreads, out placeHolder);
//while (availableThreads != maxThreads)
//{
// ThreadPool.GetAvailableThreads(out availableThreads, out placeHolder);
//}
//return;
}
public void setNeuronInput(object o)
{
try
{
//Console.WriteLine("Thread is working");
Neurons[arrayI].input[arrayX] = network.Layers[layerIndex - 1].Neurons[arrayX].output;
}
catch(Exception e)
{
Console.WriteLine(e);
Console.WriteLine("ArrayI is : " + arrayI);
Console.WriteLine("ArrayX is : " + arrayX);
Console.ReadLine();
}
}
I am just starting to use multi-threading, and I am trying to build a console application that starts to count with 2 different threads when the user hits the Enter key, and stops counting when the Enter key is pressed a second time, and then outputs the count for both threads (I realize that with my code, these will be 2 different numbers). I set this up, but for some reason, one of the numbers is usually negative.There is also quite a bit of a delay before I receive count output. Why am I getting negative counts, why is the delay so long, and how can I correct this?
My code so far;
class Program
{
static void Main(string[] args)
{
System.Threading.Thread threadA = new Thread(ThreadA);
System.Threading.Thread threadB = new Thread(ThreadB);
Console.WriteLine("Once you press enter, this application will count as high as it can until you press enter again.");
ConsoleKeyInfo info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
threadA.Start();
threadB.Start();
}
}
private static bool continueCounting = true;
static void ThreadA()
{
int count = 0;
for (int i = 0; i < int.MaxValue ; i++)
{
count++;
}
ConsoleKeyInfo info2 = Console.ReadKey();
if (info2.Key == ConsoleKey.Enter)
continueCounting = false;
Console.WriteLine(count);
}
static void ThreadB()
{
int count = 0;
while (continueCounting)
{
count++;
}
Console.WriteLine(count);
Console.ReadLine();
}
}
one of the numbers is usually negative
That's because there was no limit guard on the ThreadB loop. It was entirely possible for count to reach MaxValue then wrap around to negative maxvalue.
I also put all keyboard checks in your main thread where they arguably should be. It is here that we set continueCounting to false when the second enter key is pressed.
I also made continueCounting volatile as it is being used by multiple threads and its value should not be CPU optimised/cached.
Try this code, this fixes the delay you were experiencing; allows both threads to count at once; and exit ASAP when the enter key is pressed.
class Program
{
#region Static fields
private static volatile bool continueCounting = true;
#endregion
#region Methods
static void Main(string[] args)
{
var threadA = new Thread(ThreadA);
var threadB = new Thread(ThreadB);
Console.WriteLine(
"Once you press enter, this application will count as high as it can until you press enter again.");
var info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
threadA.Start();
threadB.Start();
}
info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
continueCounting = false;
}
Console.ReadLine();
}
static void ThreadA()
{
var count = 0;
for (var i = 0; i < int.MaxValue && continueCounting; i++)
{
count++;
}
Console.WriteLine($"A: {count}");
}
static void ThreadB()
{
var count = 0;
while (continueCounting && count < int.MaxValue)
{
count++;
}
Console.WriteLine($"B: {count}");
}
#endregion
}
I have a probably simple question about the task factory. I have to following code:
In this task is a loop that is polling data from the RS232 and a counter that stops polling after 10 times. After this "doCollect" will be set to false.
And now comes the strange thing: The task runs repeatedly. The caller code is:
// class Main()
RS232DataAquisition _RS232DataAquisition = new RS232DataAquisition();
public override void Run()
{
System.Diagnostics.Stopwatch timeout = new System.Diagnostics.Stopwatch();
timeout.Start();
_RS232DataAquisition.Start();
while ((timeout.ElapsedMilliseconds <= (dataGatherTime_inSeconds * 1000)) && _RS232DataAquisition.DoCollect)
{
System.Threading.Thread.Sleep(100);
}
timeout.Stop();
_RS232DataAquisition.Stop();
}
Per my understanding the Run() function should start the thread and return into the while-loop waiting for the thread to finish. But it never does?!
Here's the code for ReadDataFromRS232:
// sealed class RS232DataAquisition
private bool doCollect = false;
public bool DoCollect
{
get { return doCollect; }
}
public void Start()
{
doCollect = true;
currentTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
this.ReadDataFromRS232();
});
}
private void ReadDataFromRS232(int NumtoRead = 10)
{
var port = new System.IO.Ports.SerialPort(PortName);
int waitCount = 5;
var portExists = System.IO.Ports.SerialPort.GetPortNames().Any(x => x == PortName);
if (!portExists)
{
throw new ArgumentException("Port does not exist!");
}
while (port.IsOpen && waitCount-- > 0)
{
doCollect = false;
Wait();
}
doCollect = true;
if (!port.IsOpen)
{
port.Open();
port.NewLine = _NewLine;
port.ReadTimeout = 2000;
int number;
try { }
finally { }
port.Write("flashon\r");
while (doCollect && (_readCounter <= NumtoRead))
{
string s;
try
{
s = port.ReadLine();
}
catch
{
s = "-1";
}
int i;
if (int.TryParse(s, out i))
{
number = Convert.ToInt32(s, 10);
}
else
{
number = 0;
}
lock (thisLock) _data.Add(number);
_readCounter++;
}
port.Write("flashoff\r");
port.Close();
port.Dispose();
Wait(); Wait();
}
}
private void Wait()
{
System.Threading.Thread.Sleep(10);
System.Threading.Thread.SpinWait(1);
}
I don't get, why "ReadDataFromRS232" is beeing repeated until the timeout stops this task.
Thank you for any help :)
EDIT: Added some missing code.
As Dennis said the problem seemed to come from the missing volatile. It works now even though I have no idea why it didn't before.
I have a function that reads numbers from console and writes them to queue and a massive of threads that should read numbers from queue, calculate factorials and write it to file.
static void Main(string[] args)
{
int threadsNumber = 0;
Console.WriteLine("Enter the number of threads: ");
while ((Int32.TryParse(Console.ReadLine(), out threadsNumber) == false)||(threadsNumber <= 0))
{
Console.WriteLine("You need to enter a positive number!");
}
Console.Clear();
Queue<int> numbersQueue = new Queue<int>();
Thread [] threadMas = new Thread[threadsNumber];
for (int i = 0; i < threadsNumber; i++)
{
threadMas[i] = new Thread(() => ThreadProc.ThreadProcStart(numbersQueue));
threadMas[i].Start();
}
//some code...
ThreadProc:
class ThreadProc
{
private static object locker = new object();
public static void ThreadProcStart(Queue<int> queue)
{
while (true)
{
int num = Deq(queue); //Checks if queue is empty. If not -
//Returns first element
if (num != -1)
{
BigInteger bigInt = Factorial.FactTree(num); //factorical
Writer.WriteToFile(num + " factorial: " + bigInt, "result.txt"); //write to file
}
else
{
// Here I need to add something
Thread.Sleep(0);
}
}
}
public static int Deq(Queue<int> queue)
{
lock (locker)
{
if (queue.Count != 0)
{
return queue.Dequeue();
}
return -1;
}
}
}
I need to stop all threads when all calculations are done. How can i mark thread as "unactive" when the queue is empty without actually aborting it?
Use BlockingCollection, which underneath the covers uses ConcurrentQueue. Your code will be soooo much simpler and you won't have to worry about subtle locking bugs.
Your code would then look something like this:
static void Main(string[] args)
{
int threadsNumber = 0;
Console.WriteLine("Enter the number of threads: ");
while ((Int32.TryParse(Console.ReadLine(), out threadsNumber) == false) || (threadsNumber <= 0))
{
Console.WriteLine("You need to enter a positive number!");
}
Console.Clear();
BlockingCollection<int> queue = new BlockingCollection<int>();
Thread[] threadMas = new Thread[threadsNumber];
for (int i = 0; i < threadsNumber; i++)
{
threadMas[i] = new Thread(ProcessQueue);
threadMas[i].Start(queue);
}
string userInput = null;
do
{
Console.WriteLine("Enter a number: ");
userInput = Console.ReadLine();
if (userInput != "stop") {
queue.Add(int.Parse(userInput)); // These numbers get process by the threads in parallel.
}
} while (userInput != "stop");
queue.CompleteAdding(); // Use this to signal that no more items will be added to the queue.
// Now the main thread exits.
// But the program stays alive until the other threads finish
// clearing the queue.
}
private static void ProcessQueue(object data)
{
BlockingCollection<int> queue = (BlockingCollection<int>)data;
foreach (var num in queue.GetConsumingEnumerable()) // This will automatically exit the loop once CompleteAdding is called and the queue is empty.
{
BigInteger bigInt = Factorial.FactTree(num); //factorical
Writer.WriteToFile(num + " factorial: " + bigInt, "result.txt"); //write to file
}
}
I try to synchronize three threads (named "1", "2" and "3") using Semaphore class. They have to print a string into console respecting consequence: 1->2->3. Here is my code:
class MyThread
{
public Thread Thrd;
static Semaphore sem = new Semaphore(1, 1);
static int flag = 1;
public MyThread(string name)
{
Thrd = new Thread(this.Run);
Thrd.Name = name;
Thrd.Start();
}
void Run()
{
sem.WaitOne();
if (Convert.ToInt32(Thrd.Name) == flag)
{
Console.WriteLine("Thread " + Thrd.Name);
flag++;
}
if (flag == 4)
flag = 1;
Thread.Sleep(300);
sem.Release();
}
}
class SemaphoreDemo
{
static void Main()
{
for (int i = 0; i < 10; i++)
{
MyThread mt1 = new MyThread("1");
MyThread mt2 = new MyThread("2");
MyThread mt3 = new MyThread("3");
mt1.Thrd.Join();
mt2.Thrd.Join();
mt3.Thrd.Join();
}
}
}
But sometimes strings from threads #2 and #3 are not seen. Where is my mistake and how can I fix this problem?
Thank you very much!
The problem is that sometimes a thread will acquire the semaphore out of order, and you don't have any retry logic. Take a look at your Run method.
void Run()
{
sem.WaitOne();
if (Convert.ToInt32(Thrd.Name) == flag)
{
Console.WriteLine("Thread " + Thrd.Name);
flag++;
}
if (flag == 4)
flag = 1;
Thread.Sleep(300);
sem.Release();
}
Now, what happens if the thread named "3" acquires the semaphore first? flag is equal to 1, so the conditional code won't be executed. The thread will just sleep for 300 milliseconds and then exit. If you want this to work, you have to make the thread retry:
void Run()
{
bool success = false;
while (!success)
{
sem.WaitOne();
if (Convert.ToInt32(Thrd.Name) == flag)
{
Console.WriteLine("Thread " + Thrd.Name);
flag++;
success = true;
}
sem.Release();
if (!success)
{
// let somebody else try
Thread.Sleep(300);
}
}
}
That will make your sample work as expected.
I suspect that this is just an exercise to see how threading and semaphores work. Note, however, that a Mutex is usually more appropriate than a Semaphore with a maximum count of 1.
Note also that there are other ways to make threads execute in sequence, although truthfully if you're going to sequence your threads then you probably don't need more than one thread. Unless those threads are doing other things and they only need to sequence once--or infrequently.