I am a beginner C# coder so I don't know anything about Task or threads. I wrote this code and I want to use some kind of Parallel or Thread processing.
The code consist in two DataTable (A & B) and I have to compare each cell value of A to all cells of B. B consist in one column and several rows. A can be millions of cells. I do it using for loops. this is the part of the code I would like to parallelize to speed up the process:
private DataTable CalculosPrincipales(DataTable Prof, DataTable Prop, DataTable Rango)
{
DataTable dt = new DataTable();
dt.Columns.Add("Prof Evaluar", typeof(double));
dt.Columns.Add("Profundidad", typeof(double));
dt.Columns.Add("Promedio", typeof(double));
dt.Columns.Add("Sumatoria", typeof(double));
dt.Columns.Add("n", typeof(double));
if (int.TryParse(box_Z.Text, out int z))
{
}
var step = (progressBar.Properties.Maximum - (Int32)progressBar.EditValue)/z;
for (int i = 0; i < Rango.Rows.Count-1; i++)
{
dt.Rows.Add(Rango.Rows[i][0], Rango.Rows[i][1], 0, 0 , 0);
}
double prof_celda;
double prof_rango;
double prop_celda;
for (int i = 0; i < Prop.Rows.Count; i++)
{
for (int j = 0; j < Prop.Columns.Count; j++)
{
prop_celda = Convert.ToDouble(Prop.Rows[i][j]);
if (prop_celda != nullvalue)
{
for (int k = 0; k < Rango.Rows.Count; k++)
{
prof_celda = Convert.ToDouble(Prof.Rows[i][j]);
prof_rango = Convert.ToDouble(Rango.Rows[k][0]);
if (prof_celda < prof_rango)
{
dt.Rows[k][3] = Convert.ToDouble(dt.Rows[k][3]) + prop_celda;
dt.Rows[k][4] = Convert.ToInt32(dt.Rows[k][4]) + 1;
break;
}
}
}
}
progressBar.PerformStep();
Application.DoEvents();
}
for (int i = 0; i < dt.Rows.Count; i++)
{
if (Convert.ToInt32(dt.Rows[i][4]) == 0)
{
dt.Rows[i].Delete();
i -= 1;
}
}
return dt;
}
This code runs fast if tabla A has 10000 of cells, it takes 5 min when 200000 cells and 20 min when 1000000.
This is an example of parallelisation of your algorithm. However, using the DataTable introduces some performance penalties. You should consider using more suitable classes.
I made the following changes:
Extracted the calculation into a separate class.
Split the calculation into n tasks.
Added support for cancellation via CancellationTokenSource
Replaced active progress reporting with passive one.
Added exception handling
Everything now works in the background. You no longer block or slow down the UI, you just execute the calculation and let it call you back when it finishes.
You can set the number of threads manually, or you can let the algorithm use the the number of CPU cores, which maximizes the performance.
Please note that it's not an ideal implementation, it's just an an example and it's not tested.
It seems to me, that your description does not quite match the code (you talked about 2 input tables, but the code works with 3 - aren't Prop and Prof the same?)
using System;
using System.Data;
using System.Threading;
using System.Threading.Tasks;
public class ParallelCalculation
{
public delegate void CompletionHandler(DataTable result, Exception exception);
public DataTable Prof, Prop, Rango;
class Part
{
public DataTable Result;
public int FromRow, ToRow;
public float Progress;
public Exception Exception;
}
DataTable result;
Part[] parts;
Task[] tasks;
CancellationToken cancellation;
CompletionHandler callback;
public async void Run(CompletionHandler callback, CancellationToken token, int threadCount = 0)
{
this.cancellation = token;
this.callback = callback;
await Task.Factory.StartNew(Perform, threadCount);
}
async void Perform(object state)
{
int threadCount = (int)state;
try
{
// Create table for results
result = new DataTable();
result.Columns.Add("Prof Evaluar", typeof(double));
result.Columns.Add("Profundidad", typeof(double));
result.Columns.Add("Promedio", typeof(double));
result.Columns.Add("Sumatoria", typeof(double));
result.Columns.Add("n", typeof(double));
for (int i = 0; i < Rango.Rows.Count; i++)
result.Rows.Add(Rango.Rows[i][0], Rango.Rows[i][1], 0, 0, 0);
// Split calculation into n tasks. Tasks work in parallel,
// each one processes it's own stripe of data, defined by the instance of the Part class.
int n = threadCount > 0 ? threadCount : Environment.ProcessorCount;
tasks = new Task[n];
parts = new Part[n];
int rowsPerTask = Prof.Rows.Count / n;
int rest = Prof.Rows.Count % n;
for (int i = 0, from = 0, to = 0; i < n; ++i, --rest, from = to)
{
to = from + rowsPerTask + (rest > 0 ? 1 : 0);
parts[i] = new Part { FromRow = from, ToRow = to };
tasks[i] = Task.Factory.StartNew(CalculatePart, parts[i]);
}
// Wait until all partial calculations are finished
await Task.WhenAll(tasks);
// Sum partial results to the main result table (and find the first exception, if any)
Exception e = null;
foreach (var part in parts)
{
e = e ?? part.Exception;
for (int row = 0; row < result.Rows.Count; ++row)
{
result.Rows[row][3] = Convert.ToDouble(result.Rows[row][3]) + Convert.ToDouble(part.Result.Rows[row][3]);
result.Rows[row][4] = Convert.ToInt32(result.Rows[row][4]) + Convert.ToInt32(part.Result.Rows[row][4]);
}
}
// Remove empty rows from results
for (int i = 0; i < result.Rows.Count; i++)
{
if (Convert.ToInt32(result.Rows[i][4]) == 0)
{
result.Rows[i].Delete();
i -= 1;
}
}
// Call back
callback?.Invoke(result, e);
}
catch (Exception e)
{
callback?.Invoke(null, e);
}
}
void CalculatePart(object state)
{
var part = (Part)state;
try
{
// Create our own table for partial results.
part.Result = this.result.Copy();
var result = part.Result; // Just a shortcut
int cols = Prop.Columns.Count;
int steps = cols * (part.ToRow - part.FromRow);
for (int i = part.FromRow, step = 1; i < part.ToRow; i++)
{
for (int j = 0; j < cols; j++, step++)
{
var prop_celda_obj = Prop.Rows[i][j];
if (prop_celda_obj != DBNull.Value)
{
double prop_celda = Convert.ToDouble(prop_celda_obj);
double prof_celda = Convert.ToDouble(Prof.Rows[i][j]);
for (int k = 0; k < Rango.Rows.Count; k++)
{
//double prof_celda = Convert.ToDouble(Prof.Rows[i][j]);
double prof_rango = Convert.ToDouble(Rango.Rows[k][0]);
if (prof_celda < prof_rango)
{
result.Rows[k][3] = Convert.ToDouble(result.Rows[k][3]) + prop_celda;
result.Rows[k][4] = Convert.ToDouble(result.Rows[k][4]) + 1;
break;
}
}
}
part.Progress = step / (float)steps;
if (cancellation.IsCancellationRequested)
return;
}
}
}
catch (Exception e)
{
part.Exception = e;
}
}
public float Progress()
{
float sum = 0.0f;
foreach (var part in parts)
sum += part.Progress;
return sum / parts.Length;
}
}
The following code is an example of using the above class in a Form. You'll have to adapt it a bit, probably.
partial class MyForm {
Button btnStartStop;
ProgressBar progressBar;
// Do this somewhere:
// btnStartStop.Click += BtnStartStop_Click;
int threads = 0; // 0 means "The number of CPU cores"
DataTable Prof, Prop, Rango; // You have to provide these values
// The final results will be stored here:
DataTable Result;
CancellationTokenSource cancellation;
ParallelCalculation calculation;
System.Windows.Forms.Timer progressTimer;
void BtnStartStop_Click(object sender, EventArgs e)
{
if (calculation != null)
cancellation.Cancel();
else
StartCalculation();
}
void StartCalculation()
{
cancellation = new CancellationTokenSource();
calculation = new ParallelCalculation { Prof = this.Prof, Prop = this.Prop, Rango = this.Rango };
calculation.Run(Finished, cancellation.Token, threads);
progressBar.Value = 0;
progressTimer = new System.Windows.Forms.Timer(components) { Interval = 100 };
progressTimer.Tick += ProgressTimer_Tick;
progressTimer.Start();
UpdateUI();
}
void Finished(DataTable table, Exception e)
{
BeginInvoke((Action)delegate
{
Result = table;
progressBar.Value = (int)(calculation.Progress() * 100);
progressTimer.Stop();
progressTimer.Tick -= ProgressTimer_Tick;
calculation = null;
UpdateUI();
});
}
private void ProgressTimer_Tick(object sender, EventArgs e)
{
if (calculation != null)
progressBar.Value = (int)(calculation.Progress() * 100);
}
void UpdateUI()
{
btnStartStop.Text = calculation == null ? "Start" : "Stop";
}
}
Related
The system needs a way of taking input from txtBox.
I then need the system to take the number input, 1-10. And repeat the ticket and file creation for that x amount of times.
This code also creates a file on the pc with the Lottery ticket in it.
the files have to be named LottoKupon1, LottoKupon2 and so on, this needs to match user input of course.
this is for creation of file and folder
namespace Lottery
{
internal class FolderCreater
{
static string folderName = #"C:\lotto";
public static string fileName = #"C:\lotto\LottoKupon.txt";
public static void CreateFolder()
{
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
else if (!File.Exists(fileName))
{
File.Create(fileName);
}
else { }
}
}
}
This is for creation of Lottry Ticket
namespace Lottery
{
// the system needs a way of taking input
// from txtBox, int user = int.Parse(txtBox.Text.Trim()); which this line does
// i then need the system to take the number input, 1-10.
// and repeat the ticket and file creation for that x amount of times.
public partial class MainWindow : Window
{
public List<long> ListOfAllArrays = new List<long>();
int i = 1;
Random randNum = new Random();
public MainWindow()
{
InitializeComponent();
}
public void Lotto ()
{
StreamWriter sw = new StreamWriter(FolderCreater.fileName);
sw.WriteLine(" " + "Lotto " + DateTime.Now.ToString("dd/MM/yyyy\n"));
sw.WriteLine(" " + "1-uge\n" + " LYN-LOTTO\n");
Random randNum = new Random();
int[][] AllArrays = new int[10][];
for (int i = 0; i < 10; i++)
{
AllArrays[i] = new int[7];
}
int RowNr = 0;
foreach (int[] row in AllArrays)
{
RowNr++;
sw.Write(RowNr + ". ");
for (int j = 0; j < 7; j++)
{
int number = randNum.Next(1, 37);
while (row.Any(n => n == number))
{
number = randNum.Next(1, 37);
}
row[j] = number;
}
Array.Sort(row);
for(int l = 0; l < 7; l++)
{
sw.Write(row[l].ToString("00") + " ");
}
sw.Write("\n");
}
TestIfSame(AllArrays);
if (CheckBox.IsChecked == true)
{
sw.WriteLine("\n****** Joker Tal ******");
int[][] AllJokerRows = new int[2][];
for (int i = 0; i < 2; i++)
{
AllJokerRows[i] = new int[7];
}
foreach (int[] n in AllJokerRows)
{
sw.Write(" ");
for (int i = 0; i < 7; i++)
{
var JokerNumber = randNum.Next(1, 10);
n[i] = JokerNumber;
}
Array.Sort(n);
for (int u = 0; u < 7; u++)
{
sw.Write(n[u] + " ");
}
sw.Write("\n");
}
}
sw.Close();
}
public void TestIfSame(int[][] AllArrays)
{
//List<long> ListOfAllArrays = new List<long>();
for (int i = 0; i < AllArrays.Length; i++)
{
ListOfAllArrays.Add(MakesLongNumber(AllArrays[i]));
}
for (int i = 0; i < AllArrays.Length; i++)
{
long temp = ListOfAllArrays[0];
ListOfAllArrays.Remove(ListOfAllArrays[0]);
if (ListOfAllArrays.Contains(MakesLongNumber(AllArrays[i])))
{
Lotto();
}
else
{
ListOfAllArrays.Add(temp);
}
}
long MakesLongNumber(int[] row)
{
string a = "";
for (int i = 0; i < row.Length; i++)
{
a += row[i].ToString();
}
return Convert.ToInt64(a);
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
}
private void cmdOk_Click_1(object sender, RoutedEventArgs e)
{
FolderCreater.CreateFolder();
Lotto();
// add a ListBox.Items.Add(); within this needs to be the command for the Lottery ticket, so i can have it shown on a list box.
}
**This is for a Lottery assignment, its on a lower level of coding, so no answer that is way too complicated, hope you understand. please ask questions if needed.
I tried a dew things with a for loop around the first void which took user input, but i could not make it work.
the code is expected to create files and Lottery ticket depending on users input**
I have console application with numerical calculation, which I am trying to parallel using the ThreadPool.
I got object state as class (simple-data-passing):
public class DataContainer
{
public double[,] Exa;
public double[] EQ;
public int iStart;
public int iEnd;
}
Definition for WaitCallback
private void Calculate(object state)
{
DataContainer data = state as DataContainer;
for (int m = data.iStart; m < data.iEnd; m++)
{
double temp= 0.0;
for (int i = 0; i < 500000; i++)
{
for (int j = i + 1; j < 500000; j++)
{
//Some-Long-Calculation based on data.Exa-around 200 math operation with results of double EQC
if (EQC> temp) { temp= EQC; } //line performance issue-temp is declared in first for-loop block;
}
}
}
}
Execution:
WaitCallback waitCallback = Calculate;
const int numberOfThreads = 100;
ThreadPool.SetMaxThreads(30, 100);
for (int i = 0; i < numberOfThreads; i++)
{
DataContainer tempContainer = new DataContainer();
tempContainer.Exa = Exa;
tempContainer.EQ = EQ;
tempContainer.iStart = CalculateStart(i);
tempContainer.iEnd = CalculateEnd(i);
ThreadPool.QueueUserWorkItem(waitCallback, tempContainer);
}
int numberOfTotalThreads = 0;
int numberOfMaxThreads = 0;
int numberOfWorkingThreads = 0;
int temp = 0;
//do-while - waiting to finish all calculation
do
{
ThreadPool.GetAvailableThreads(out numberOfTotalThreads, out temp);
ThreadPool.GetMaxThreads(out numberOfMaxThreads, out temp);
numberOfWorkingThreads = numberOfMaxThreads - numberOfTotalThreads;
Console.WriteLine("Number of working threads {0}", numberOfWorkingThreads);
Thread.Sleep(1000);
} while (numberOfWorkingThreads > 0);
So one marked line:
if (EQC> temp) { temp= EQC; }
Time exeuction of program slow down from 40s to 600s.
Could you advice how these line should be written to avoid that problem?
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 a function that takes a variable as a parameter and returns a calculated result. That function splits up into other functions each doing their own calculation. I need the function to run multi threaded.
My code:
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
var localK = k;
var localI = i;
Image bestPic;
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));//THIS IS WHERE THE WRONG VALUES ARE ASSIGNED BECAUSE OF CROSS THREADING
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
}
}).Start();
}
}
All I need is the function getBestPic to run multi threaded. But how do I run the function getBestPic multi threaded and make the assigning of the returned result to the bestPic variable atomic?
My entire program if needed: This is a montage program.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Drawing;
namespace test
{
public partial class Form1 : Form
{
private static readonly Object thisLock = new Object();
private Graphics g;
private Bitmap returnImg;
private Bitmap pic;
private int done = 0;
private int pictureWidthAndLength = 200;
private string inputPicName = "test";
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime dtStart = DateTime.Now;
pic = new Bitmap(inputPicName + ".jpg");
//MessageBox.Show(pic.GetPixel(1,1).ToArgb().ToString());
//MessageBox.Show(pic.Width.ToString() + " x " + pic.Height.ToString());
returnImg = new Bitmap(pic.Width * pictureWidthAndLength, pic.Height * pictureWidthAndLength);
using (g = Graphics.FromImage(returnImg))
{
Color clr;
int[] argb = new int[4];
for (int i = 0; i < pic.Width; i++)
{
for (int k = 0; k < pic.Height; k++)
{
clr = pic.GetPixel(i, k);
argb[0] = clr.A;
argb[1] = clr.R;
argb[2] = clr.G;
argb[3] = clr.B;
var localK = k;
var localI = i;
Image bestPic;
if (cbxthreading.Checked)
{
new Thread(() =>
{
bestPic = new Bitmap(getBestPic(argb));
lock (thisLock)
{
g.DrawImage(bestPic, localI * bestPic.Width, localK * bestPic.Height, bestPic.Width, bestPic.Height);
done++;
}
}).Start();
}
else
{
//Single threaded
bestPic = new Bitmap(getBestPic(argb));
g.DrawImage(bestPic, localI * pictureWidthAndLength, localK * pictureWidthAndLength, pictureWidthAndLength, pictureWidthAndLength);
}
//MessageBox.Show(getBestPic(argb));
}
}
if (cbxthreading.Checked)
{
int loopNum = pic.Width * pic.Height;
while (done < loopNum) { }
}
}
DateTime dtEnd = DateTime.Now;
MessageBox.Show((dtEnd - dtStart).ToString());
}
//Get picture that is best suited to replace pixel
private string getBestPic(int[] argb)
{
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argb);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}
// smaller the value, closer the camparison
private int compareARGB(int[] one, int[] two)
{
int [] tmp = new int[4];
tmp[0] = Convert.ToInt32(Math.Abs(one[0] - two[0]));
tmp[1] = Convert.ToInt32(Math.Abs(one[1] - two[1]));
tmp[2] = Convert.ToInt32(Math.Abs(one[2] - two[2]));
tmp[3] = Convert.ToInt32(Math.Abs(one[3] - two[3]));
return (tmp[0] + tmp[1] + tmp[2] + tmp[3]);
}
//return int arry with size 4 containing the argb values
private int[] getAverageRGB(Bitmap img)
{
Color clr;
int aplha = 0;
int red = 0;
int green = 0;
int blue = 0;
for (int i = 0; i < img.Width; i++)
{
for (int k = 0; k < img.Height; k++)
{
clr = img.GetPixel(i, k);
aplha += clr.A;
red += clr.R;
green += clr.G;
blue += clr.B;
}
}
aplha = aplha / (img.Width * img.Height);
red = red / (img.Width * img.Height);
green = green / (img.Width * img.Height);
blue = blue / (img.Width * img.Height);
int[] re = new int[] {aplha,red,green,blue};
return re;
}
private void button2_Click(object sender, EventArgs e)
{
returnImg.Save(inputPicName+".bmp");
MessageBox.Show("Done!");
}
}
}
The single thread functionality works, but takes long. The multi threaded functionality also finishes in a third of the time of the single threaded, but the result is not correct.
getBestPic() method runs multi-thread as I understand. But the problem is the argb parameter. You initialize it ones and then overwrite its values in for loops.argb is reference type, so only the reference is passed to getBestPic(), so it's referenced values get changed while processed in getBestPic().
I would try to pass it by Value or move int[] argb = new int[4];line to the inside of the second for loop, so you every time initialize new variable. More on passing reference type params here.
Just create a copy of the Value of your argb in the getBestPic() method and use it instead of using the original one
private string getBestPic(int[] argb)
{
int[] argbCopy = argb.ToArray();
int numOfpics = 5;
int[] currentBest = new int[2];
currentBest[0] = 255;
currentBest[1] = 150;
for (int i = 0; i < numOfpics; i++)
{
int compare = compareARGB(getAverageRGB(new Bitmap((i + 1).ToString()+".jpg")), argbCopy);
if (compare < currentBest[0])
{
currentBest[0] = compare;
currentBest[1] = i + 1;
}
}
return currentBest[1].ToString() + ".jpg";
}
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);
}
}
}