I've got the following multithreaded code for calculating Euler's number. I'm new in multithreaded programming and maybe I'm missing something. For some reason countdown.Wait() is not waiting for all the threads and totalSum is different almost every time. It looks like it skips some of the intermediate sums.
public static class Program
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
private static CountdownEvent countDown = new CountdownEvent(threadsCount);
private static Object locker = new Object();
private static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateEulerNumber), threadIndex);
}
countDown.Wait();
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static void CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
totalSum = BigRational.Add(totalSum, sum);
stopwatch.Stop();
lock (locker)
{
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToDecimalString(40));
}
Console.WriteLine();
}
countDown.Signal();
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
#usr made a good point: you better use ConcurrentStack<T> or ConcurrentQueue<T> as detailed in http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx.
Also, it's better to implement your algorithm using Task.Factory as explained by Alexandra Rusina in http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx. As per the mentioned resources, your solution may look like something following (giving you general idea)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
ConcurrentStack<int> cs = new ConcurrentStack<int>();
public static double YourFunction(int SomeNumber)
{
// computation of result
return result;
}
private void start_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "";
label1.Content = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{
int j = i;
var t = Task.Factory.StartNew(() =>
{
int result = YourFunctiopn(j);
this.Dispatcher.BeginInvoke(new Action(() =>
cs.Add(result ))
, null);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
}
}
Hope this will help. Rgds,
You are using the CountDownEvent wrongly.CountDownEvent are for signalling and you dont need this in current program. You can do this with tasks:
public class Class1
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
public static void Main1(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<Task<BigRational>> tasks = new List<Task<BigRational>>();
//Create the tasks
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
Task<BigRational> task = new Task<BigRational>((data)=>
{
return CalculateEulerNumber(data);
},threadIndex);
tasks.Add(task);
}
foreach (var task in tasks)
{
task.Start();
}
//Wait for tasks
Task.WaitAll(tasks.ToArray());
//Add the results
foreach (var task in tasks)
{
totalSum = BigRational.Add(totalSum, task.Result);
}
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static BigRational CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
stopwatch.Stop();
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToString());
}
Console.WriteLine();
return sum;
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
So create the task and each task can run seperately and return individual sum. You can then add the results to create the total sum. There is no need of locks either.
Related
I wrote a test program to see how much faster different kind of loops with pointers are and encountered a strange behaviuor where if i add a Console.WriteLine("1: " + sum) after the first loop some of the loops get faster and another becomes slower.
So how does this affect the perfomance of the loop because it seems like it does not interact with the loops at all.
My example code has the line which affects loop perfomance commented out to show the normal performance and if I uncomment it the speed changes.
class Program
{
static void Main(string[] args)
{
Class1 c = new Class1();
c.Do();
}
}
public class Class1
{
public unsafe int n = 1000000000;
public unsafe int[] arr;
public Class1 ()
{
arr = new int[n];
for (int i = 0; i < arr.Length; i++)
{
arr[i] = 2;
}
}
public void Do ()
{
int sum = 1;
Stopwatch sw = new Stopwatch();
sw.Start();
sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
sw.Stop();
//Console.WriteLine("1: " + sum);
Console.WriteLine("1: " + sw.ElapsedMilliseconds);
unsafe
{
sw.Reset();
sw.Start();
sum = 0;
for (int i = 0; i < arr.Length; i++)
{
sum += arr[i];
}
sw.Stop();
Console.WriteLine("2: " + sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
sum = 0;
fixed (int* start = arr)
{
for (int i = 0; i < arr.Length; i++)
{
sum += *(start + i);
}
}
sw.Stop();
Console.WriteLine("3: " + sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
sum = 0;
fixed (int* start = arr)
{
int* iter = start;
var remaining = arr.Length;
while (remaining-- > 0)
{
sum += *iter;
iter++;
}
}
sw.Stop();
Console.WriteLine("4: " + sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
sum = 0;
fixed (int* start = arr)
{
int* end = start + n;
int* iter = start - 1;
while (iter++ < end)
{
sum += *iter;
}
}
sw.Stop();
Console.WriteLine("5: " + sw.ElapsedMilliseconds);
}
}
}
output:
1: 2082
2: 2038
3: 1800
4: 2061
5: 1724
output with uncommented line:
1: 2000000000
1: 1949
2: 1953
3: 1998
4: 2055
5: 1724
I tested it multiple times to see if it was just a random difference but it seems to be consistent.
so I'm in a bit confused as to how I'm supposed to do something. I've got 5 threads that are doing a basic task and they are generated with a for loop in main. I've already used a semaphore that limits the amount of threads running at a time as that's a part of the exercise, what I've got left is to make sure that threads that are next to each other (they're numbered 0-4 using the loop) don't run simultaneously. What I've got as an idea is to block every odd or even thread(it doesn't really matter) but I can't figure out how to both let two threads in and at the same time block every odd one. Is there a specific method for that, or maybe if there is another way, like letting three in at first and somehow not letting the second one in but letting the third one. I'll leave what I've got done so far:
edit: For clarification the way it has to be thought about is actually a bit different then what I initially asked about. So if 1 is running both 0 and 2 aren't allowed to run. But if 0 is running both 4 and 1 aren't allowed to run either. I'm pretty sure that it's obvious that if 4 is running 0 and 3 aren't allowed to work etc. .
using System.Threading;
namespace StudentProblem
{
public class StudentProblem
{
static Semaphore stop = new Semaphore(2,2);
static Semaphore gate = new Semaphore(3,3);
public static void Student(Object o)
{
var r = new Random();
var num = (int) o;
while (true)
{
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
//gate.WaitOne();
stop.WaitOne();
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
//gate.Release();
stop.Release();
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
studentThreads[i] = new Thread(StudentProblem.Student);
studentThreads[i].Start(i);
}
}
}
}
In the end I decided to ditch the whole multiple semaphore approach and went with the old and trusty way. I'll add my solution here. It's not that great, but it works.
using System;
using System.Collections.Generic;
using System.Threading;
namespace testing
{
public class StudentProblem
{
public static List<StudentProblem> allProblems = new List<StudentProblem>();
static Semaphore eatingGate = new Semaphore(2, 2);
private object id;
private bool eating = false;
public StudentProblem(object o)
{
id = o;
}
public object Id
{
get
{
return this.id;
}
}
public bool Eating
{
get
{
return this.eating;
}
}
public void DoStuff()
{
var r = new Random();
var num = (int)this.Id;
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
while (true)
{
for (int i = 0; i < num; i++)
Console.Write("_");
int indexBehind = 0;
int indexFront = 0;
for (int i = 0; i < allProblems.Count; i++)
{
if(num == 0)
{
indexBehind = 4;
}
else
{
indexBehind = num - 1;
}
if(num == 4)
{
indexFront = 0;
}
else
{
indexFront = num + 1;
}
check:
if (allProblems[indexBehind].Eating != true && allProblems[indexFront].Eating != true)
{
if (eatingGate.WaitOne())
{
this.eating = true;
Thread.Sleep(250);//poigrai si s timeout-a
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(1000, 2000));
for (int j = 0; j < num; j++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
this.eating = false;
eatingGate.Release();
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
}
else
{
goto check;
}
}
else
{
goto check;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
StudentProblem.allProblems.Add(new StudentProblem(i));
studentThreads[i] = new Thread(StudentProblem.allProblems[i].DoStuff);
studentThreads[i].Start();
}
}
}
}
I ran the code below to test speed of some common uses in my program for UOM's and was quite surprised. With the results: All tests were run 1 million times in debug mode (run mode gave similar differences). It seems there is no real advantage in using structs for UOMs from a speed point of view so can anyone tell what any advantages would be? (I have a big number crunching program and this is of huge interest to me). If the example code is wrong in any way below, please let me know also. What I really want is the most convenient way to handle UOMs without making the code verbose (UOM * UOM rather than UOM.Value * UOM.Value would be best but its apparently not the most speed efficient). All times in ms.
Multply doubles 7
Multply struct fields 8
Multply struct property 232
Multply temperature struct using overloaded * operator 141
Multply class fields 7
Multiply & Load doubles into object array 692
Multiply struct fields & Load into object array 719
Multiply struct fields & Load new struct into object array 926
Multiply structs with overloaded operator a load struct into object array 906
Multiply class fields & load into object array 697
Multiply class fields & load new class into object array 964
Multiply class using overloaded * operator & load class into object array 948
public class TestSpeed
{
public class TempClass
{
public double value=100;
private double v;
public TempClass(double v)
{
this.v = v;
}
public static TempClass operator *(TempClass t1, TempClass t2)
{
return new TempClass(t1.value * t2.value);
}
}
public struct TempStruct
{
public double value;
public TempStruct(double v)
{
value = v;
}
public double GetTemp
{
get { return value; }
set { this.value = value; }
}
public static TempStruct operator *(TempStruct t1, TempStruct t2)
{
return new TempStruct(t1.value * t2.value);
}
}
[TestMethod]
public void TestDouble()
{
double doubleValue = 100;
TempStruct t = new TempStruct();
TempStruct Tres= new TempStruct(100);
TempClass tclass = new TempClass(100);
double res;
var watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res = doubleValue*doubleValue;
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multply doubles "+ elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
Tres.value = t.value * t.value;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multply struct fields " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
Tres.GetTemp = t.GetTemp * t.GetTemp;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multply struct property " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
Tres = t * t;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multply temperature struct using overloaded * operator " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res = tclass.value * tclass.value;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multply class fields " + elapsedMs.ToString());
}
[TestMethod]
public void TestDoubleArray()
{
double doublevalue = 100;
TempStruct t = new TempStruct();
TempStruct Tres = new TempStruct(100);
TempClass tclass = new TempClass(100);
object[] res = new object[10000000];
var watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = doublevalue * doublevalue;
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply & Load doubles into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = t.value * t.value;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply struct fields & Load into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = new TempStruct(t.value * t.value);
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply struct fields & Load new struct into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = t * t;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply structs with overloaded operator a load struct into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = tclass.value * tclass.value;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply class fields & load into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = new TempClass(tclass.value * tclass.value);
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply class fields & load new class into object array " + elapsedMs.ToString());
watch = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
res[i] = tclass * tclass;
}
watch.Stop();
elapsedMs = watch.ElapsedMilliseconds;
Debug.WriteLine("Multiply class using overloaded * operator & load class into object array " + elapsedMs.ToString());
}
}
The difference between struct and class is memory allocation. Using class, you have a very small overhead. So you wont be able to notice the performance overhead.
Then the point of using struct is not using reference. Hence you dont need to worry about the value is changed in 1 method may affect another method.
I am trying to create an application to record the time elapsed per machine using simple arithmetic operations.
Using console application, with parameters of number of loop and the threads to use with the code below:
public static Int64 IterationCount { get; set; }
static void Main(string[] args)
{
int iterations = int.Parse(args[0]);
int threads = int.Parse(args[1]);
IterationCount = iterations * 1000000000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < threads; i++)
{
Task.Factory.StartNew(() => Calculate());
Task.WaitAll();
}
sw.Stop();
Console.WriteLine("Elapsed={0}", sw.Elapsed);
}
And my Calculate method:
private static void Calculate()
{
for (int i = 0; i < IterationCount; i++)
{
a = 1 + 2;
b = 1 - 2;
c = 1 * 2;
a = 1 / 2;
}
}
Now I think this is not working because the result of my elapsed time when I entered 10 iterations (I am multiplying the first parameter to 1 billion: 10 * 1,000,000,000) and 4 threads is:
00:00:00:0119747
Any thing I missed?
Your call to Task.WaitAll() has no effect as the signature of the function is
public static void WaitAll(params Task[] tasks).
You see, you can supply a variable count of Tasks to wait for and you call this function with no task; so it will not wait at all.
If you replace your code by the following, you will see the effect.
Task[] tasks = new Task[threads];
for (int i = 0; i < threads; i++)
{
tasks[i] = Task.Factory.StartNew(() => Calculate());
}
Task.WaitAll(tasks);
Turns out my comment is accurate. If I copy the contents of your Calculate method into Visual Studio:
private static void Calculate()
{
for (int i = 0; i < IterationCount; i++)
{
a = 1 + 2;
b = 1 - 2;
c = 1 * 2;
d = 1 / 2;
}
}
after compilation, the generated C# code looks like this:
private static void Calculate()
{
for (int i = 0; i < Program.IterationCount; i++)
{
Program.a = 3;
Program.b = -1;
Program.c = 2;
Program.d = 0;
}
}
Instead, you're going to have to make one of the constants into a variable:
private static void Calculate()
{
int x = 1;
for (int i = 0; i < IterationCount; i++)
{
a = x + 2;
b = x - 2;
c = x * 2;
d = x / 2;
}
}
This code becomes:
private static void Calculate()
{
int x = 1;
for (int i = 0; i < Program.IterationCount; i++)
{
Program.a = x + 2;
Program.b = x - 2;
Program.c = x * 2;
Program.d = x / 2;
}
}
I have been trying to implement a distributed depth first search in c#. I have beem successful upto a certain point but have got a synchronisation error. I am not able to rectify the error. What i am trying to do is make each node communicate with one other using task parallel dataflow and thereby i attain parallelism in DFS. Below is my code:
public class DFS
{
static List<string> traversedList = new List<string>();
static List<string> parentList = new List<string>();
static Thread[] thread_array;
static BufferBlock<Object> buffer1 = new BufferBlock<Object>();
public static void Main(string[] args)
{
int N = 100;
int M = N * 4;
int P = N * 16;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<string> global_list = new List<string>();
StreamReader file = new StreamReader(args[args.Length - 2]);
string text = file.ReadToEnd();
string[] lines = text.Split('\n');
string[][] array1 = new string[lines.Length][];
for (int i = 0; i < lines.Length; i++)
{
lines[i] = lines[i].Trim();
string[] words = lines[i].Split(' ');
array1[i] = new string[words.Length];
for (int j = 0; j < words.Length; j++)
{
array1[i][j] = words[j];
}
}
StreamWriter sr = new StreamWriter("E:\\Newtext1.txt");
for (int i = 0; i < array1.Length; i++)
{
for (int j = 0; j < array1[i].Length; j++)
{
if (j != 0)
{
sr.Write(array1[i][0] + ":" + array1[i][j]);
Console.WriteLine(array1[i][0] + ":" + array1[i][j]);
sr.Write(sr.NewLine);
}
}
}
int start_no = Convert.ToInt32(args[args.Length - 1]);
thread_array = new Thread[lines.Length];
string first_message = "root";
buffer1.Post(first_message);
buffer1.Post(array1);
buffer1.Post(start_no);
buffer1.Post(1);
for (int t = 1; t < lines.Length; t++)
{
Console.WriteLine("thread" + t);
thread_array[t] = new Thread(new ThreadStart(thread_run));
thread_array[t].Name = t.ToString();
lock (thread_array[t])
{
Console.WriteLine("working");
thread_array[t].Start();
thread_array[t].Join();
}
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
Console.ReadLine();
}
private static void dfs(string[][] array, int point)
{
for (int z = 1; z < array[point].Length; z++)
{
if ((!traversedList.Contains(array[point][z])))
{
traversedList.Add(array[point][z]);
parentList.Add(point.ToString());
dfs(array, int.Parse(array[point][z]));
}
}
return;
}
public static void thread_run()
{
try
{
string parent;
string[][] array1;
int point;
int id;
parent = (string)buffer1.Receive();
array1 = (string[][])buffer1.Receive();
point = (int)buffer1.Receive();
id = (int)buffer1.Receive();
object value;
Console.WriteLine("times");
if (Thread.CurrentThread.Name.Equals(point.ToString()))
{
if (!traversedList.Contains(point.ToString()))
{
Console.WriteLine("Node:" + point + " Parent:" + parent + " Id:" + id);
traversedList.Add(point.ToString());
parent = point.ToString();
for (int x = 1; x < array1[point].Length; x++)
{
Console.WriteLine("times");
if (buffer1.TryReceive(out value))
{
array1 = (string[][])value;
}
if (buffer1.TryReceive(out value))
{
id = (int)buffer1.Receive();
}
id++;
buffer1.Post(parent);
buffer1.Post(array1);
buffer1.Post(x);
buffer1.Post(id);
Console.WriteLine("times");
Monitor.PulseAll(Thread.CurrentThread);
}
//return;
}
else
{
buffer1.Post(parent);
buffer1.Post(array1);
buffer1.Post(point);
buffer1.Post(id);
Console.WriteLine("working 1");
Monitor.PulseAll(Thread.CurrentThread);
}
}
else
{
Console.WriteLine("working 2");
Monitor.Wait(Thread.CurrentThread);
}
//Console.WriteLine(parent);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
There various issues with your code.
Incorrect use of locking and "touching" the traversedList from multiple threads is the most obvious problem.
More importantly, your code doesn't really use Dataflow, it uses BufferBlock in a manner similar to ConcurrentQueue or any other concurrent collection. The whole point of dataflow is to use ActionBlocks instead of threads to simplify processing. By default an action block will use only a single thread for processing but you can specify as many threads as you want through the DataflowBlockOptions class.
ActionBlocks have their own input and output buffers so you don't have to add additional BufferBlocks just for buffering.
Passing multiple related values to a block is another problem, as it can lead to errors and makes the code confusing. Creating a data structure to hold all the values doesn't cost anything.
Assuming you use this class to hold processing message:
public class PointMessage
{
public string Message { get; set; }
public string[][] Lines{get;set;}
public int Point { get; set; }
public int ID { get; set; }
}
You can create an ActionBlock to process these messages like this:
static ActionBlock<PointMessage> _block;
...
var options = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = ExecutionDataflowBlockOptions.Unbounded };
_block=new ActionBlock<PointMessage>(msg=>ProcessMessage(msg),options);
And process each message like this:
private static void ProcessMessage(PointMessage arg)
{
if (...)
{
...
arg.ID++;
_block.Post(arg);
}
else
{
...
_block.Post(arg);
}
}
If your function returns a value, you can use a TransformBlock instead of an ActionBlock.
I don't understand what your code does so I won't try to rewrite it using DataFlow. If you clean it up a bit, it will be easier to help.
The issue is that the Thread needs to own Monitor in order to call Wait. So you need to lock on Monitor.PulseAll aswell as Monitor.Wait in order to ensure that you don't get any more errors like this.
If you need me to explain locking to you, open another question and I'll explain it in full! :)
EDIT: Ignore my post - Read the post from #PanagiotisKanavos instead...
This won't compile, but will set you in the right direction for using locks:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
public class DFS
{
static List<string> traversedList = new List<string>();
static List<string> parentList = new List<string>();
static Thread[] thread_array;
//static BufferBlock<Object> buffer1 = new BufferBlock<Object>();
public static void Main(string[] args)
{
int N = 100;
int M = N * 4;
int P = N * 16;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<string> global_list = new List<string>();
StreamReader file = new StreamReader(args[args.Length - 2]);
string text = file.ReadToEnd();
string[] lines = text.Split('\n');
string[][] array1 = new string[lines.Length][];
for (int i = 0; i < lines.Length; i++)
{
lines[i] = lines[i].Trim();
string[] words = lines[i].Split(' ');
array1[i] = new string[words.Length];
for (int j = 0; j < words.Length; j++)
{
array1[i][j] = words[j];
}
}
StreamWriter sr = new StreamWriter("E:\\Newtext1.txt");
for (int i = 0; i < array1.Length; i++)
{
for (int j = 0; j < array1[i].Length; j++)
{
if (j != 0)
{
sr.Write(array1[i][0] + ":" + array1[i][j]);
Console.WriteLine(array1[i][0] + ":" + array1[i][j]);
sr.Write(sr.NewLine);
}
}
}
int start_no = Convert.ToInt32(args[args.Length - 1]);
thread_array = new Thread[lines.Length];
string first_message = "root";
//buffer1.Post(first_message);
//buffer1.Post(array1);
//buffer1.Post(start_no);
//buffer1.Post(1);
for (int t = 1; t < lines.Length; t++)
{
Console.WriteLine("thread" + t);
thread_array[t] = new Thread(new ThreadStart(thread_run));
thread_array[t].Name = t.ToString();
lock (thread_array[t])
{
Console.WriteLine("working");
thread_array[t].Start();
thread_array[t].Join();
}
}
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
Console.ReadLine();
}
private static void dfs(string[][] array, int point)
{
for (int z = 1; z < array[point].Length; z++)
{
if ((!traversedList.Contains(array[point][z])))
{
traversedList.Add(array[point][z]);
parentList.Add(point.ToString());
dfs(array, int.Parse(array[point][z]));
}
}
return;
}
bool busy;
private readonly object syncLock = new object();
public static void thread_run()
{
try
{
string parent;
string[][] array1;
int point;
int id;
//parent = (string)buffer1.Receive();
//array1 = (string[][])buffer1.Receive();
//point = (int)buffer1.Receive();
//id = (int)buffer1.Receive();
object value;
Console.WriteLine("times");
if (Thread.CurrentThread.Name.Equals("Point.ToString()"))
{
if (!traversedList.Contains("Point.ToString()"))
{
for (int x = 1; x < 99999; x++)
{
Console.WriteLine("times");
//if (buffer1.TryReceive(out value))
//{
// array1 = (string[][])value;
//}
//if (buffer1.TryReceive(out value))
//{
// id = (int)buffer1.Receive();
//}
//id++;
//buffer1.Post(parent);
//buffer1.Post(array1);
//buffer1.Post(x);
//buffer1.Post(id);
Console.WriteLine("times");
lock (syncLock)
{
while (busy)
{
busy = false;
Monitor.PulseAll(Thread.CurrentThread);
}
busy = true; // we've got it!
}
}
//return;
}
else
{
//buffer1.Post(parent);
//buffer1.Post(array1);
//buffer1.Post(point);
//buffer1.Post(id);
lock (syncLock)
{
while (busy)
{
busy = false;
Monitor.PulseAll(Thread.CurrentThread);
}
busy = true; // we've got it!
}
}
}
else
{
Console.WriteLine("working 2");
lock (syncLock)
{
while (busy)
{
Monitor.Wait(Thread.CurrentThread);
}
busy = true; // we've got it!
}
}
//Console.WriteLine(parent);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}