I have the following code inside my c# console application, where i am calling a method called getInfo in parallel using WhenAll() method, as follow:-
class Program
{
static int concurrentrequests = int.Parse(ConfigurationManager.AppSettings["ConcurrentRequests"]);
static SemaphoreSlim throttler = new SemaphoreSlim(initialCount: concurrentrequests);
private static ScanInfo getInfo(string website)
{
throttler.Wait();
ScanInfo si = new ScanInfo();
int counter = 1;
try
{
//code goes here..
}
catch (Exception e)
{
//code goes here
}
finally
{
throttler.Release();
}
}
return si;
}
static void Main(string[] args)
{
Marketing ipfd = new Marketing();
try
{
using (WebClient wc = new WebClient()) // call the PM API to get the account id
{
//code goes here
}
}
catch (Exception e)
{
}
var tasks = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();
var results = Task.WhenAll(tasks);
//code goes here..
}
}
but i am getting this exception:-
Argument 1: cannot convert from
System.Collections.Generic.List<Sales.ScanInfo> to
System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task>
so can anyone advice why i am getting this error?
var tasks = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();
var results = Task.WhenAll(tasks);
tasks contains the results. YOu dont have to do any waiting at all. What make syou think you do. So just do
var results = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();
Can anyone help and determine if this is my error or the unlikely .Net bug?
The code below shows a Main() routine starting 10 tasks, using the DoNothing() method as the underlying method and a SemphoreSlim that will allow 3 tasks to run simultaneously.
Then the Main() waits for a duration of time:
Thread.Sleep(3000);
After the wait we cancel all tasks:
cancel.Cancel();
At which point I expected the .ContinueWith(..) to take over:
doNothingTasks.Add(
Task.Factory.StartNew(() => doNng.DoNothing(canToken), canToken)
.ContinueWith(_ => { Console.WriteLine(..);
}, TaskContinuationOptions.OnlyOnCanceled)
Instead I get an exception on the following line in the DoNothing() routine:
This is unexpected.
Output at exception is:
Can anyone explain???
Complete code:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace TestAsync
{
class Program
{
private static readonly SemaphoreSlim Broker = new SemaphoreSlim(3);
static void Main(string[] args)
{
var doNothingTasks = new List<Task>();
using (var cancel = new CancellationTokenSource())
{
var canToken = cancel.Token;
for (var i = 0; i < 10; ++i)
{
var doNng = new TestCancellationToken(i);
doNothingTasks.Add(
Task.Factory.StartNew(() =>
doNng.DoNothing(canToken), canToken)
.ContinueWith(_ => { Console.WriteLine(
$"{DateTime.Now:HH:mm:ss.ffff}. " +
$"{new string('.', 25)} {doNng.Name} " +
$"WAS CANCELLED {new string('.', 10)}");
}, TaskContinuationOptions.OnlyOnCanceled)
);
}
Thread.Sleep(3000);
cancel.Cancel();
try
{
Task.WaitAll(doNothingTasks.ToArray());
}
catch (AggregateException ae)
{
var fae = ae.Flatten();
foreach (var ex in fae.InnerExceptions)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"{ex.GetType().Name}: {ex.Message}");
}
Console.WriteLine("Done.");
Console.ReadKey();
}
}
class TestCancellationToken
{
private readonly Random _rnd;
public int Name { get; }
public TestCancellationToken(int inx)
{
_rnd = new Random(inx);
Name = inx;
}
public void DoNothing(CancellationToken canToken)
{
for (var i = 0; ; ++i)
{
if (canToken.IsCancellationRequested)
canToken.ThrowIfCancellationRequested();
Broker.Wait();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"Test {Name} round: {i}, aquire time");
var sleepPeriod = _rnd.Next(750) + 50;
Thread.Sleep(sleepPeriod);
Broker.Release();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"Test {Name} round: {i}, release time: {sleepPeriod}");
}
}
}
}
}
I have a C# windows form program that uses three threads.
*The first thread is responsible for reading files from input folder and reading all text from each file then send data as string to the second thread using a Queue.
*The second thread is responsible on parsing the string got from the first thread, if the string was a number then send this number to the third thread also using a Queue.
*The third thread is responsible on creating file for the number got from thread 2.
Also I should have a Timer that runs thread 1 every 4 seconds for example until pressing stop.( should thread 2 and thread 3 when thread 1 runs after 4 seconds ?)
Note That the three threads should be running in parallel and should be in the correct order Thread 1 then Thread 2 then Thread 3 and should be getting and sending data for each other.
Below is an image for what i described below and some of the code that I used in my program.
Please I want your help I'm stuck in this ....
Code is :
form1.cs Class
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
public partial class Form1 : Form
{
public ConcurrentQueue<string> _queue = new ConcurrentQueue<string>();
public Queue<string> Queue1result = new Queue<string>();
public Queue<string> TestQueue = new Queue<string>();
public Queue<string> Queue2result = new Queue<string>();
public Form1()
{
InitializeComponent();
}
/* private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
} */
private void timer1_Tick(object sender, EventArgs e)
{
isonline();
}
public void isonline()
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
MessageBox.Show(files[0]);
var a = files[1];
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox1.Text = folderBrowserDialog1.SelectedPath;
/* try
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
var output = folderBrowserDialog2.SelectedPath;
FileInfo[] f = dir.GetFiles();
Queue<FileInfo> Q = new Queue<FileInfo>(f);
while (Q.Count > 0)
{
FileInfo current = Q.Dequeue();
Console.WriteLine(current);
// Process 'current'
}
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
} */
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog2.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox2.Text = folderBrowserDialog2.SelectedPath;
}
}
private void button3_Click(object sender, EventArgs e)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}", result);
//var firstThread = new Thread1();
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(TestQueue); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result,output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
//thread1.Start();
//thread1.Join();
//thread2.Start();
//thread1.Join(TimeSpan.Zero);
//Console.WriteLine(thread1.Join(TimeSpan.Zero));
// new System.Threading.Timer (ThreadTimer, "Thread 1 Started working...", 5000, 1000);
}
private void button4_Click(object sender, EventArgs e)
{
}
/* public void ThreadTimer (object data)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}",result);
}
*/
public bool Thread1Start(string input, string output)
{
var firstThread = new Thread1();
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
TestQueue = Queue1result;
thread1.Start();
Console.WriteLine("thread 1 start");
var state = thread1.Join(TimeSpan.Zero);
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(Queue1result); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result, output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
return state;
}
}
}
Thread1.cs class
here using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
class Thread1
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 1");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> Readfiles(string inputDirectoryPath, string outputDirectoryPath)
{ Queue<string> thread1Queue = new Queue<string>();
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = fi.DirectoryName + "\\" + fi.Name;
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string readText = File.ReadAllText(filePath);
thread1Queue.Enqueue(readText);
Console.WriteLine(readText);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
}
return thread1Queue;
}
}
}
Thread2.cs class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread2
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 2");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> test(Queue<string> list)
{
Queue<string> thread2Queue = new Queue<string>();
while (list.Count > 0)
{
try
{
var a = list.Dequeue();
Console.WriteLine(a);
int j;
if (Int32.TryParse(a, out j))
{
Console.WriteLine("parsed the string {0} to integer and sent to thread 3", j);
thread2Queue.Enqueue(a);
}
else
Console.WriteLine("String could not be parsed to integer.");
Console.WriteLine("thread 2 parsing string from thread 1");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
return thread2Queue;
}
}
}
Thread3.cs Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread3
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 3");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public void CreateFiles(Queue<string> list, string outputDirectoryPath)
{
while (list.Count > 0)
{
string format = "MM-dd-yyyy--HH-mm-ss";
DateTime date = DateTime.Now;
string filename = date.ToString(format);
string file = outputDirectoryPath + "\\" + filename + ".txt";
var a = list.Dequeue();
FileInfo fi = new FileInfo(file);
if (!fi.Exists)
{
fi.Create().Dispose();
System.IO.File.WriteAllText(file,a);
Console.WriteLine("creating new text file {{0}}",file);
}
else
{
Console.WriteLine("file already exists");
}
Console.WriteLine(a);
Console.WriteLine("Thread 3 creating File with date name");
Console.WriteLine(date.ToString(format));
}
}
}
}
Thank you very much for your help .
I won´t comment on all, there´s too much stuff to talk about, but let´s have a look at your first thread.
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
This line will create a thread that will replace the existing instance in your field Queue1Result (have a look at naming conventions, please!) once after reading some files (if existing). If executed again, The existing queue goes out of scope and will be replaced with a new one, probably not what you want to do.
You need to create those queue instances just once (type to use is ConcurrentQueue), those should then be used as a parameter running the thread procedure. So, redeclare the queues to readonly ConcurrentQueue to create the instances for your fields(give them a good "speaking" name, btw).
public readonly ConcurrentQueue<string> _textFromFilesQueue = new ConcurrentQueue<string>();
Once started, you want to regularly look after files again, so your code has to contain a loop.
This loop to be executed should be terminable from outside / other threads using a CancellationToken. Lets add a CancellationTokenSource to Form 1:
public CancellationTokenSource CancellationTokenSource { get; set; }
Your execution code for the first thread could / should look like this:
public void Readfiles(string inputDirectoryPath, string outputDirectoryPath, ConcurrentQueue<string> queue, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = Path.Combine(fi.DirectoryName, fi.Name);
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string textFromFile = File.ReadAllText(filePath);
queue.Enqueue(textFromFile);
Console.WriteLine(textFromFile);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
Thread.Sleep(TimeSpan.FromSeconds(5));
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
Throw excep;
}
}
}
Do not build up a path by concatenating strings, use Path.Combine instead. Also, exceptions that happened should just be rethrown to ensure correct handling from other threads / tasks.
I would recommend using the TPL mechanisms instead of threads, it grants the system more flexibility in handling the tasks to be executed in a parallel manner. Have a look here : https://msdn.microsoft.com/de-de/library/dd460717(v=vs.110).aspx
So, creating and executing this task:
CancellationTokenSource = new CancellationTokenSource();
Task task = new Task(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token));
task.Start();
Stopping the task:
CancellationTokenSource.Cancel();
Be sure not to overwrite the TokenSource without calling Cancel(), else you are losing the ability to stop the tasks that have already started...
EDIT: If you really need to ignore TPL, here is the example to execute the reading method with a thread:
Thread thread = new Thread(new ThreadStart(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token)));
thread.Resume();
Use very simple and clear code:
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = Task.Run(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("path", "searchPattern"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = Task.Run(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = Task.Run(() =>
{
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
string path = ""; // set fileName
File.WriteAllText(path, number);
}
});
Task.WaitAll(readFiles, processNumbers, createFiles);
It guarantees the execution in the correct order.
You can easily add cancellation using CancellationTokenSource.
Ok. Here is a working application that uses threads and timer.
It is assumed that execution all threads is faster than the timer interval.
New threads starts with each timer tick. The old threads will continue to work if they have not yet ended.
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
Button stopButton;
System.Windows.Forms.Timer timer;
public Form1()
{
//InitializeComponent();
stopButton = new Button { Parent = this, Text = "Stop" };
stopButton.Click += StopButton_Click;
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
timer.Start();
Text = "Start";
}
private void StopButton_Click(object sender, EventArgs e)
{
timer.Stop();
Text = "Stop";
}
private void Timer_Tick(object sender, EventArgs e)
{
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = new Thread(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("./Folder", "*.txt"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = new Thread(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = new Thread(() =>
{
int counter = 0;
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
File.WriteAllText("./Folder2/" + counter + ".txt", number);
counter++;
}
});
readFiles.Start();
processNumbers.Start();
createFiles.Start();
readFiles.Join();
processNumbers.Join();
createFiles.Join();
}
}
}
I'm initializing and starting five threads in my Testing Class:
[Test]
public void ReportGeneratorFiveThreadTest()
{
var threads = new List<ReportGeneratorThread>();
var logger = new Log4NetLogger(typeof(ReportGeneratorThreadTest));
for (var i = 0; i < 5; i++)
{
var estimatedReportSize = EstimatedReportSize.Normal;
var thread = new ReportGeneratorThread(logger, new ReportGenerator(20), estimatedReportSize, new ManualResetEvent(false));
thread.Name = string.Format("ReportGeneratorThread{0}", i);
threads.Add(thread);
}
threads.ForEach(t => t.Start());
}
And I'm starting all threads by calling following method in ReportGeneratorThread class:
public void Start()
{
this.running = true;
this.t = new Thread(this.GenerateReport());
this.t.SetApartmentState(ApartmentState.STA);
this.t.Start();
}
Which calls a GenerateReport() method in order to perform an operation:
public void GenerateReport()
{
var didwork = false;
try
{
didwork = this.reportGenerator.GenerateReport(this.estimatedReportSize);
}
catch (Exception e)
{
this.log.LogError(ReportGenerator.CorrelationIdForPickingReport, string.Format(CultureInfo.InvariantCulture, "System"), string.Format(CultureInfo.InvariantCulture, "Error during report generation."), 0, e);
this.doneEvent.Reset();
Debug.WriteLine("Thread is aborted !!!");
}
finally
{
if (!didwork)
{
Thread.Sleep(Settings.Default.ReportGenerationInterval);
}
}
}
My purpose is to inform my main thread once a thread among all five threads gets aborted (an exception is thrown in GenerateReport() method) and restart it in my main thread afterwards. I have tried using ManualResetEvent for that purpose, but it seems like it is not the proper class to use for this purpose. Any approaches ?.
I adapted the following code from one I found online. Works ok but is not running continuously and pulling in new tweets. What do I need to change? Help appreciated.
private static void Stream_FilteredStreamExample()
{
SqlConnection conn = new SqlConnection(#"Data Source=********************");
conn.Open();
for (; ; )
{
try
{
var stream = Stream.CreateFilteredStream();
//stream.AddLocation(Geo.GenerateLocation(-180, -90, 180, 90));
stream.AddTweetLanguageFilter(Language.English);
stream.AddTrack("#TubeStrike");
var timer = Stopwatch.StartNew();
stream.MatchingTweetReceived += (sender, args) =>
{
var tweet = args.Tweet;
if (timer.ElapsedMilliseconds > 1000)
{
Console.WriteLine("{0}, {1}", tweet.IdStr, tweet.Text);
timer.Restart();
}
};
stream.StartStreamMatchingAllConditions();
}
catch (Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
}
}
You want to use the following code:
stream.StreamStopped += (sender, args) =>
{
stream.StartStreamMatchingAllConditions();
};