This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to change stack size for a .NET program?
I want to change the stack size for the following console application:
using System;
using System.IO;
class Test {
static int n;
static bool[] us;
static int[,] matr;
static void dfs(int a) {
us[a] = true;
for (int b = 0; b < n; b++) {
if (!us[b]) {
dfs(b);
}
}
}
static void Main() {
StreamReader input = new StreamReader("input.txt");
StreamWriter output = new StreamWriter("output.txt");
string[] snum = input.ReadLine().Split(' ');
n = int.Parse(snum[0]); // number of vertices
int m = int.Parse(snum[1]); // number of edges
us = new bool[n];
matr = new int[n, n];
for (int i = 0; i < m; i++) {
snum = input.ReadLine().Split(' ');
int a = int.Parse(snum[0]) - 1, b = int.Parse(snum[1]) - 1;
matr[a, b] = matr[b, a] = 1;
}
for (int i = 0; i < n; i++) {
if (!us[i]) {
dfs(i);
}
}
input.Close();
output.Close();
}
}
When n is aprox. 100,000, the depth of dfs is aprox. 100,000 and the application throws a StackOverflowException.
I know that the default stack size is 1 MB, but I do not know how to change it.
int stackSize = 1024*1024*64;
Thread th = new Thread( ()=>
{
//YourCode
},
stackSize);
th.Start();
th.Join();
The easiest way to specify a larger stack size is to create a new thread -- there's a constructor overload that allows you to specify the size. Move the logic to a new method, then, in the Main method, create a new thread with a larger stack size to run the new method. Example:
static void Main() {
const int stackSize = 0x400000;
var thread = new Thread(NewMethod, stackSize);
thread.Start();
thread.Join();
}
static void NewMethod() {
StreamReader input = new StreamReader("input.txt");
StreamWriter output = new StreamWriter("output.txt");
string[] snum = input.ReadLine().Split(' ');
n = int.Parse(snum[0]);
int m = int.Parse(snum[1]);
us = new bool[n];
matr = new int[n, n];
for (int i = 0; i < m; i++) {
snum = input.ReadLine().Split(' ');
int a = int.Parse(snum[0]) - 1, b = int.Parse(snum[1]) - 1;
matr[a, b] = matr[b, a] = 1;
}
for (int i = 0; i < n; i++) {
if (!us[i]) {
dfs(i);
}
}
input.Close();
output.Close();
}
You can also use EDITBIN, if you're not able to change the source code. See this answer for details: https://stackoverflow.com/a/2556970/385844
Related
I'm making a program that generates the "names" (random lines of text from the ASCII) that are the names of movies in this instance. I should follow them up with a "name" of a director for each (can also be generated from the ASCII), and after that the random year that is the year the "movie" was made (from 1896 to 2021).
I have two separate functions that randomize the names of the movies and directors, but I'm confused with the supposed placement of the Console.Writeline which the intelligence only allows inside their own loops. Otherwise it doesn't seem to be able to use the values "directorname" and "moviename".
I need it to write the names in a single line, ai. (KHGTJ, KGHTJF).
Also I need a way to generate a random year from 1896 to 2021 that is printed after the names of the movie, and director, ai. (KFJU, MDDOS, 1922).
private static void GenerateRandomNames()
{
Random random = new Random();
char y = (char)65;
for (int p = 0; p < 100; p++)
{
string directorname = "";
for (int m = 0; m < 5; m++)
{
int b = random.Next(65, 90);
y = (char)b;
directorname += y;
}
Console.WriteLine(directorname);
}
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
Console.WriteLine(moviename);
}
Console.WriteLine();
I need to fix the plecement of the Console.Writeline() so it can print both names in the same line, and be able to print the year after them.
I've tried placing the Console.Writeline() outside the loops, but of course it can't then use the name. But this way it prints them the wrong way.
If you want to have minimal changes in your code, you can use the following code:
private static void GenerateRandomNames()
{
//a separate thing for the names of the directors (ASCII)
// then for the years they were made (1896-2021)
//they should all be printed in the end ie. (KGMFK, JDBDJ, 1922)
Random rnd = new Random();
char x = (char)65;
for (int j = 0; j < 100; j++)
{
string directors = "";
string moviename = "";
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
moviename += x;
}
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
x = (char)a;
directors += x;
}
Console.WriteLine("( "+directors +", "+ moviename + ", " +rnd.Next(1896, 2021).ToString()+" )");
}
Console.WriteLine();
}
and result:
Not sure if it is good to answer this type of question, but answering it anyway.
Since you only want other 5-letter words and 4-digit numbers ranging from 1896 - 2021,
Just get another variable 'b' and do the same as you did for 'a', like :
int b = rnd.Next(65,90) ;
y = char(b) ;
director name += y ;
and to get the year value, you can use this :
year = rnd.Next(1896,2021)
So, by combining all of the above, you have the code like this :
internal class Program
{
private static void GenerateRandomNames()
{
Random rnd = new Random();
char x = (char)65;
char y = (char) 65 ;
for (int j = 0; j < 100; j++)
{
string moviename = "";
string directorName = "";
int year = rnd.Next(1896,2021);
for (int i = 0; i < 5; i++)
{
int a = rnd.Next(65, 90);
int b = rnd.Next(65, 90);
x = (char)a;
moviename += x;
y = (char)a;
directorName += x;
}
Console.WriteLine(moviename);
Console.WriteLine(directorName);
Console.WriteLine(year);
}
Console.WriteLine();
}
static void Main(string[] args)
{
GenerateRandomNames();
}
}
The task becomes easier if you extract the creation of a random name to a new method. This allows you to call it twice easily. I moved the random object to the class (making it a class field), so that it can be reused in different places.
internal class Program
{
private static readonly Random _rnd = new Random();
private static string CreateRandomName(int minLength, int maxLength)
{
string name = "";
for (int i = 0; i < _rnd.Next(minLength, maxLength + 1); i++)
{
char c = (char)_rnd.Next((int)'A', (int)'Z' + 1);
name += c;
}
return name;
}
private static void WriteRandomNames()
{
for (int i = 0; i < 100; i++)
{
string movie = CreateRandomName(4, 40);
string director = CreateRandomName(3, 30);
int year = _rnd.Next(1896, 2022);
Console.WriteLine($"{movie}, {director}, {year}");
}
Console.WriteLine();
}
static void Main(string[] args)
{
WriteRandomNames();
}
}
Note that the second parameter of the Next(Int32, Int32) method is the exclusive upper bound. Therefore I added 1.
output:
HATRHKYAHQTGS, NCPQ, 1999
QVJAYOTTISN, LJTGJDMB, 2018
JEXJDICLRMZFRV, GJPZHFBHOTR, 1932
SKFINIGVYUIIVBD, DIZSKOS, 1958
LWWGSEIZT, AMDW, 1950
OAVZVQVFPPBY, SPEZZE, 2008
YLNTZZIXOCNENGYUL, URNJMK, 1962
ONIN, WUITIL, 1987
RJUXGORWDVQRILDWWKSDWF, MOEYPZQPV, 1946
YUQSSOPZTCTRM, UEPPXIVGERG, 1994
KILWEYC, QJZOTLKFMVPHUE, 1915
Wow, in the time it took me to write an answer, three or more others appeared. They all seem like pretty good answers to me, but since I went to the trouble of writing this code, here you go. :)
I focused on using the same Random in different ways, because I think that's what you were asking about.
using System;
using System.Collections.Generic;
using System.Linq;
Random rnd = new Random(1950);
GenerateRandomNames();
void GenerateRandomNames()
{
for (int j = 0; j < 100; j++)
{
// here's one way to get a random string
string name = Guid.NewGuid().ToString().Substring(0, 5);
string description = new string(GetRandomCharacters(rnd.Next(5,16)).ToArray());
string cleaner = new string(GetCleanerCharacters(rnd.Next(5, 16)).ToArray());
string preferred = new string(GetPreferredRandomCharacters(rnd.Next(5, 16)).ToArray());
int year = rnd.Next(1896, DateTime.Now.Year + 1);
Console.WriteLine($"{year}\t{preferred}");
Console.WriteLine($"{year}\t{cleaner}");
Console.WriteLine($"{year}\t{name}\t{description}");
Console.WriteLine();
}
Console.WriteLine();
}
// Not readable
IEnumerable<char> GetRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
yield return Convert.ToChar(rnd.Next(0, 255));
}
}
// gives you lots of spaces
IEnumerable<char> GetCleanerCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
char c = Convert.ToChar(rnd.Next(0, 255));
if (char.IsLetter(c))
{
yield return c;
}
else
{
yield return ' ';
}
}
}
// Most readable (in my opinion), but still nonsense.
IEnumerable<char> GetPreferredRandomCharacters(int length = 5)
{
for (int i = 0; i < length; i++)
{
bool randomSpace = rnd.Next(0, 6) == 3;
if (i > 0 && randomSpace) // prevent it from starting with a space
{
yield return ' ';
continue;
}
var c = Convert.ToChar(rnd.Next(65, 91)); // uppercase letters
if (rnd.Next(0, 2) == 1)
{
c = char.ToLower(c);
}
yield return c;
}
}
What's a better way to create a random 16-digit string? I've used this code, can you suggest a more efficient or elegant way to do it?
static string Random16DigitString() {
var rand = new Random();
return $"{rand.Next(100000000).ToString().PadLeft(8, '0')}{rand.Next(100000000).ToString().PadLeft(8, '0')}";
}
PS: My reason for making this is to create a string of the form 0.0000000000000000 so I would use it in the following way:
var myString = "0." + Random16DigitString();
Your solution depends on string manipulation that will slow it down.
Try:
private static Random r = new Random();
static string Random16DigitString() {
var v = new char[16];
for (var j = 0; j < 16; j++) v[j] = (char)(r.NextDouble()*10 + 48);
return new string(v);
}
This will be faster since it doesn't depend on string operations like concatenation or interpolation. It just pokes random characters into a char array and then converts that array to a string. Executing your solution 100 million times takes about 47 seconds on my machine and my code takes about 27 seconds to produce the same results.
r.Next(10) + 48 would work in the above code but it's actually a little slower. r.Next(48,57) is even slower.
Your code could be simpler, also. $"{rand.Next(100000000):D8}{rand.Next(100000000):D8}" would do the same thing. It's about the same time to execute.
Here's the code I ended up using:
static readonly Random rnd = new Random();
static string Q() {
// https://stackoverflow.com/questions/767999/random-number-generator-only-generating-one-random-number/768001#768001
// It was decided to use a lock instead of [ThreadStatic] because this api object is designed to be used by many threads simultaneously.
lock (rnd) {
// Get a string representing a positive number greater than 0 and less than 1 with exactly 16 decimal places.
// Original implementation
//return $"0.{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
// This works but is slow
//return rnd.NextDouble().ToString("F16");
// Found a better faster way: https://stackoverflow.com/questions/48455624/generate-random-16-digit-string/48457354#48457354
var chars = new char[18];
chars[0] = '0';
chars[1] = '.';
for (var i = 2; i < 18; i++)
chars[i] = (char)(rnd.NextDouble() * 10 + 48);
return new string(chars);
}
}
Here are the tests I used (with thanks to Jim Berg for his answer)
using System;
using System.Diagnostics;
using System.Text;
namespace NetCoreApp1 {
class Program {
static void Main(string[] args) {
var sync = new object();
var rnd = new Random();
Time("method1", () => {
var value = $"{rnd.Next(100000000).ToString().PadLeft(8, '0')}{rnd.Next(100000000).ToString().PadLeft(8, '0')}";
});
Time("method2", () => {
var value = $"{rnd.Next(100000000):D8}{rnd.Next(100000000):D8}";
});
Time("next double", () => {
var value = rnd.NextDouble().ToString("F16"); // turns out surprisingly slow, even slower than the first two
});
Time("method3", () => {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // fastest
var value = new string(v);
});
Time("method3 with lock", () => {
lock (sync) {
var v = new char[16];
for (var j = 0; j < 16; j++)
v[j] = (char)(rnd.NextDouble() * 10 + 48); // a tiny bit slower with the lock
var value = new string(v);
}
});
Time("method4", () => {
var sb = new StringBuilder(16);
for (var j = 0; j < 16; j++)
sb.Append((char)(rnd.NextDouble() * 10 + 48)); // slower than method 3
var value = sb.ToString();
});
Console.WriteLine("Press Enter to exit.");
Console.ReadLine();
}
static void Time(string testName, Action action) {
var sw = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
action();
sw.Stop();
Console.WriteLine($"{testName}: {sw.ElapsedMilliseconds}ms");
}
}
}
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'm making a webshop for school and had a quick question.
I'm trying to write a code that generates a random coupon code and it actually works (did some extreme programming in Console Application), but it's simply not efficient.
static void Main(string[] args)
{
Random r = new Random();
string ALphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 4;
char[] code1 = new char[size]
char[] code2 = new char[size]
char[] code3 = new char[size]
for (int i = 0; i < size; i++)
{
code1[i] = Alphabet[r.Next(Alphabet.Length)];
code2[i] = Alphabet[r.Next(Alphabet.Length)];
code3[i] = Alphabet[r.Next(Alphabet.Length)];
}
string code4 = new string(code1);
string code5 = new string(code2);
string code6 = new string(code3);
Console.WriteLine(code4 + " - " + code5 + " - " + code6);
Console.ReadLine();
}
This works.. somehow. But I would like to see it more efficient, because when I want to generate 100 coupons... this isn't really the way to do that.
I did see something on joining strings, use string.Insert to get that " - " in between and loop it multiple times, but I couldn't get a clear tutorial on how to do that with... well this kind of code.
Anyone got a efficient and (preferable) easy solution?
=======
UPDATE!
this does end up in a database eventually
You could be using a StringBuilder for this:
StringBuilder sb = new StringBuilder();
Random r = new Random();
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 16;
for (var i = 0; i < size; i++)
{
sb.Append(Alphabet[r.Next(Alphabet.Length)]);
}
Console.WriteLine(sb.ToString());
If you want less code you can make use of a GUID and format it.
Guid.NewGuid().ToString("N").Substring(0, 16);
Update, just saw you needed some formatting between each part of the coupon, so I changed it a litle bit:
StringBuilder sb = new StringBuilder();
Random r = new Random();
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int pieces = 3, pieceSize = 4;
for (var i = 0; i < pieces; i++)
{
if(i != 0)
sb.Append(" - ");
for (var j = 0; j < pieceSize; j++)
{
sb.Append(Alphabet[r.Next(Alphabet.Length)]);
}
}
Console.WriteLine(sb.ToString());
Code is not quite good, but for school app will play I guess )
static string GenerateCoupon(Random r)
{
string Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int size = 4;
char[] code1 = new char[size];
char[] code2 = new char[size];
char[] code3 = new char[size];
for (int i = 0; i < size; i++)
{
code1[i] = Alphabet[r.Next(Alphabet.Length)];
code2[i] = Alphabet[r.Next(Alphabet.Length)];
code3[i] = Alphabet[r.Next(Alphabet.Length)];
}
string code4 = new string(code1);
string code5 = new string(code2);
string code6 = new string(code3);
return string.Format("{0}-{1}-{2}", code4, code5, code6);
}
static void Main(string[] args)
{
Random rnd = new Random();
for (int i = 0; i < 100;i++ )
Console.WriteLine(GenerateCoupon(rnd));
Console.ReadLine();
}
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);
}
}
}