In the code below I want to syncronize the reporting of the results of a list of tasks. This is working now because task.Result blocks until the task completes. However, task id = 3 takes a long time to complete and blocks all of the other finished tasks from reporting their status.
I think that I can do this by moving the reporting (Console.Write) into a .ContinueWith instruction but I don't have a UI thread so how do I get a TaskScheduler to syncronize the .ContinueWith tasks?
What I have now:
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
var tasks = new List<Task<int>>();
for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 5000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
});
tasks.Add(t);
}
foreach (var task in tasks)
{
Console.WriteLine("Completed {0} on {1}", task.Result, Thread.CurrentThread.ManagedThreadId);
}
Console.WriteLine("End of Main");
Console.ReadKey();
}
I would like to move to this or something similar but I need the Console.Write("Completed...") to all happen on the same thread:
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
for (var i = 0; i < 10; i++)
{
var num = i;
Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
}).ContinueWith(value =>
{
Console.WriteLine("Completed {0} on {1}", value.Result, Thread.CurrentThread.ManagedThreadId);
}
/* need syncronization context */);
}
Console.WriteLine("End of Main");
Console.ReadKey();
}
-- SOLUTION --
After getting some comments and reading some of the solutions this is the complete solution that does what I want. The goal here is to process severl long running tasks as fast as possible and then do something with the results of each task one at a time.
static void Main(string[] args)
{
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
var results = new BlockingCollection<int>();
Task.Factory.StartNew(() =>
{
while (!results.IsCompleted)
{
try
{
var x = results.Take();
Console.WriteLine("Completed {0} on {1}", x, Thread.CurrentThread.ManagedThreadId);
}
catch (InvalidOperationException)
{
}
}
Console.WriteLine("\r\nNo more items to take.");
});
var tasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
var num = i;
var t = Task.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
results.Add(num);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(), _ => results.CompleteAdding());
Console.WriteLine("End of Main");
Console.ReadKey();
}
You'll have to create a writer task of some sort, however, keep in mind even this task can be rescheduled onto another native or managed thread! Using the default scheduler in TPL you have no control over which managed thread receives the work.
public class ConcurrentConsole
{
private static BlockingCollection<string> output
= new BlockingCollection<string>();
public static Task CreateWriterTask(CancellationToken token)
{
return new Task(
() =>
{
while (!token.IsCancellationRequested)
{
string nextLine = output.Take(token);
Console.WriteLine(nextLine);
}
},
token);
}
public static void WriteLine(Func<string> writeLine)
{
output.Add(writeLine());
}
}
When I switched your code to use this I received the following output:
End of Main
Done 1 on 6
Completed 1 on 6
Done 5 on 9
Completed 5 on 9
Done 0 on 4
Completed 0 on 4
Done 2 on 5
Completed 2 on 13
Done 7 on 10
Completed 7 on 10
Done 4 on 8
Completed 4 on 5
Done 9 on 12
Completed 9 on 9
Done 6 on 6
Completed 6 on 5
Done 8 on 11
Completed 8 on 4
Done 3 on 7
Completed 3 on 7
Even with your code sending () => String.Format("Completed {0} on {1}"... to ConcurrentConsole.WriteLine, ensuring the ManagedThreadId would be picked up on the ConcurrentConsole Task, it still would alter which thread it ran on. Although with less variability than the executing tasks.
You can use OrderedTaskScheduler to ensure only one task completion is run at a time; however, they will run on a threadpool thread (not necessarily all on the same thread).
If you really need them all on the same thread (not just one at a time), then you can use ActionThread from the Nito.Async library. It provides a SynchronizationContext for its code, which can be picked up by FromCurrentSynchronizationContext.
I would suggest:
1) Creating a lock object
2) Create a list of strings to be written
3) Spawn a thread that loops, sleeping for a bit, then locking the list of strings, then if it isn't empty, writing all of them and emptying the list
4) Other threads then lock the list, add their status, unlock and continue.
object writeListLocker = new object();
List<string> linesToWrite = new List<string>();
// Main thread loop
for (; ; )
{
lock (writerListLocker)
{
foreach (string nextLine in linesToWrite)
Console.WriteLine(nextLine);
linesToWrite.Clear();
}
Thread.Sleep(500);
}
// Reporting threads
lock (writerListLocker)
{
linesToWrite.Add("Completed (etc.)");
}
I think you expect a result like the following.
Starting on 8
Done 1 on 11
Completed 1 on 9
Done 5 on 11
Completed 5 on 9
Done 0 on 10
Completed 0 on 9
Done 2 on 12
Completed 2 on 9
Done 7 on 16
Completed 7 on 9
Done 4 on 14
Completed 4 on 9
Done 9 on 18
Completed 9 on 9
Done 6 on 15
Completed 6 on 9
Done 8 on 17
Completed 8 on 9
Done 3 on 13
Completed 3 on 9
As below, I used the StaSynchronizationContext in my code from the Understanding SynchronizationContext where a synchronized call in one thread is explained well. Please, refer to it.
My code snippet is:
static void Main(string[] args)
{
StaSynchronizationContext context = new StaSynchronizationContext();
StaSynchronizationContext.SetSynchronizationContext(context);
Console.WriteLine("Starting on {0}", Thread.CurrentThread.ManagedThreadId);
for (var i = 0; i < 10; i++)
{
var num = i;
Task<int>.Factory.StartNew(() =>
{
if (num == 3)
{
Thread.Sleep(20000);
}
Thread.Sleep(new Random(num).Next(1000, 10000));
Console.WriteLine("Done {0} on {1}", num, Thread.CurrentThread.ManagedThreadId);
return num;
}).ContinueWith(
value =>
{
Console.WriteLine("Completed {0} on {1}", value.Result, Thread.CurrentThread.ManagedThreadId);
}
,TaskScheduler.FromCurrentSynchronizationContext());
}
Console.WriteLine("End of Main");
Console.ReadKey();
}
Related
I wrote a command line program that lets two robots (Lifeguard and Superhero) wander randomly in a 22x22 matrix until they get to a square with the # symbol.
The direction choice of the robot Superhero is in contrast to the robot Lifeguard not equally distributed. Superhero chooses the direction north 66% of the time.
I can start both robots asynchronously via the menu. While the data for Lifeguard is available relatively fast, the program freezes because of Superhero. I assumed that it does not freeze because I am programming asynchronously. Where is the error?
using System.Diagnostics;
class Program {
public static async Task Main(string[] args) {
Map map = new Map();
Roboter l = new Roboter(map.defaultMap, "Lifesaver", 'L', 9);
Roboter s = new Roboter(map.defaultMap, "Superhero", 'S', 10);
map.spreadRoboters(l, s);
View view = new View(map.defaultMap);
Stopwatch watch = new Stopwatch();
Random rand = new Random();
string input = "start";
while (input != "exit") {
Console.WriteLine("choose an option:");
Console.WriteLine("1 start asynchronously");
Console.WriteLine("2 show Map");
Console.WriteLine("3 exit.");
input = Console.ReadLine();
switch (input) {
case "1":
await StartTaskAsync(l, s, rand, watch);
break;
case "2":
view.displayMap();
break;
case "exit":
input = "exit";
break;
default:
input = "exit";
break;
}
}
}
static async Task StartTaskAsync(Roboter l, Roboter s, Random r, Stopwatch watch) {
Task < string > lifesaverTask = StartLifesaverAsync(l, r, watch);
Task < string > superheroTask = StartSuperheroAsync(s, r, watch);
List < Task < string >> taskList = new List < Task < string >> {
lifesaverTask,
superheroTask
};
/* Task<string> completedTask = await Task.WhenAny(taskList);
string result = await completedTask;
Console.WriteLine(result);*/
while (taskList.Count > 0) {
Task < string > taskResult = await Task.WhenAny(taskList);
if (taskResult == lifesaverTask) {
Console.WriteLine(lifesaverTask.Result);
} else if (taskResult == superheroTask) {
Console.WriteLine(superheroTask.Result);
}
taskList.Remove(taskResult);
}
}
static async Task < string > StartLifesaverAsync(Roboter l, Random r, Stopwatch watch) {
return await Task.Run(() => {
int steps = 1;
string[] directions = new string[] {
"NORTH",
"SOUTH",
"WEST",
"EAST"
};
watch.Start();
while (l.state != true) {
int zufall = r.Next(0, 4);
string direction = directions[zufall];
l.move(direction, l.map);
steps++;
}
watch.Stop();
long time = watch.ElapsedMilliseconds;
l.reset(1, 1);
return "Lifesaver: steps: " + (steps).ToString() + ", time: " + time.ToString() + "ms";
});
}
static async Task < string > StartSuperheroAsync(Roboter s, Random r, Stopwatch watch) {
return await Task.Run(() => {
int steps = 1;
string[] directions = new string[] {
"NORTH",
"NORTH",
"NORTH",
"NORTH",
"NORTH",
"NORTH",
"SOUTH",
"WEST",
"EAST"
};
watch.Start();
while (s.state != true) {
int zufall = r.Next(0, 9);
string direction = directions[zufall];
s.move(direction, s.map);
steps++;
}
watch.Stop();
long time = watch.ElapsedMilliseconds;
s.reset(20, 20);
return "Superhero: steps: " + (steps).ToString() + ", time: " + time.ToString() + "ms";
});
}
}
I think there are at least two things a play here.
A. while(...)
while(something != true){ can be dangerous because they can run forever. You don't say how long "the program freezes" for so I'm not sure, but you may have a case where s.move(direction,s.map); never sets s.State to true.
You may want to protect yourself. Here's one option:
...
steps++;
if(steps > 1_000) throw ApplicationException("Something went wrong. Too many steps taken");
B. await Task.Run
await Task.Run(() => { will wait until the work is done.
If you want to start the task but not wait until it's finished don't await immediately. Here's a little example:
using System.Diagnostics;
var sw = Stopwatch.StartNew();
var t = Task.Run(() => { Console.WriteLine("Task 1 starting... Thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);// Simulate a computationally heavy work
Console.WriteLine("Task 1 ending... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
});
var t2 = Task.Run(() => { Console.WriteLine("Task 2 starting... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(2000);// Simulate a computationally heavy work
Console.WriteLine("Task 2 ending... thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
});
Console.WriteLine("After starting both tasks. Task thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
await Task.WhenAll(t, t2);
Console.WriteLine("Tasks finished. Task thread ID: {0}",Thread.CurrentThread.ManagedThreadId);
Console.WriteLine(sw.Elapsed);
prints
After starting both tasks. Task thread ID: 1
Task 2 starting... thread ID: 5
Task 1 starting... Thread ID: 3
Task 1 ending... thread ID: 3
Task 2 ending... thread ID: 5
Tasks finished. Task thread ID: 5
00:00:02.0351754
I'm reading a file and wants to process 10 lines at a time.
This only works if I'm processing < 10 lines. For loop just continues and doesn't wait for the first 10 tasks to complete.
Please advise.
Below is my code :
private void btnStart_Click(object sender, EventArgs e)
{
int lctr = 0;
var tasks = new List<Task>();
foreach (string s in lines)
{
if (string.IsNullOrWhiteSpace(s) || string.IsNullOrEmpty(s))
continue;
lctr++;
tasks = new List<Task>();
if (lctr < 11)
{
Console.WriteLine(lctr + " - " + s);
tasks.Add(Task.Factory.StartNew(() => processThis(s)));
}
else
{
Console.WriteLine("Waiting ...");
Task.WaitAll(tasks.ToArray());
}
}
if (tasks.Count > 0)
Task.WaitAll(tasks.ToArray());
}
When you say "Please Advise" it gives me wide latitude to try and help. Here are my suggestions and I hope you find them "useful":
Q: "I'm reading a file and wants to process 10 lines at a time."
A: Before spawning any tasks, enqueue your test list into groups of 10 strings (and a final group that might be partial if, say, the list is 25 string long).
Here is a method to do the first part:
// Short-running method that queues up strings in batches of 10 or less
private static Queue<List<string>> enqueueBatchesOf10orLess(List<string> testData)
{
Queue<List<string>> batchesOfUpTo10 = new Queue<List<string>>();
List<string> singleBatchOfUpTo10 = new List<string>(); ;
for (int count = 0; count < testData.Count; count++)
{
if ((count % 10) == 0)
{
if(count != 0) // Skip the very first time
{
batchesOfUpTo10.Enqueue(singleBatchOfUpTo10);
singleBatchOfUpTo10 = new List<string>();
}
}
singleBatchOfUpTo10.Add(testData[count]);
}
// Leftover batch of less-than-10
if(singleBatchOfUpTo10.Count != 0)
{
batchesOfUpTo10.Enqueue(singleBatchOfUpTo10);
}
return batchesOfUpTo10;
}
Next, it appears you want to process those batches concurrently (implying that there might be some processing time that justifies doing this). Here is how you pass your "batches of 10 or less" in and receive a Task in return.
private static Task processBatch(Queue<List<string>> batches)
{
return Task.Run(() => // Return task that processes batch of 10 or less
{
var batch = batches.Dequeue();
foreach (var singleString in batch)
{
processThis(singleString);
}
});
}
...where...
private static void processThis(string s)
{
Task.Delay(100).Wait(); // Simulate long-running string processing
Console.WriteLine(s);
}
To test this out:
static void Main(string[] args)
{
// Make some test data
List<string> testData = new List<string>();
for (int i = 0; i < 25; i++) testData.Add((i + 1).ToString());
Queue<List<string>> batchesOf10OrLess = enqueueBatchesOf10orLess(testData);
List<Task> tasks = new List<Task>();
for (int i = 0; i < batchesOf10OrLess.Count; i++)
{
// Pass in the queue of batches and get a Task in return.
tasks.Add(processBatch(batchesOf10OrLess));
}
Console.WriteLine("The test data is NOT in order.");
Console.WriteLine("This is proof the tasks are running concurrently");
Task.WaitAll(tasks.ToArray());
// Pause
Console.ReadKey();
}
Here's what we get:
The test data is NOT in order.
This is proof the tasks are running concurrently
1
21
11
2
12
22
3
23
13
4
14
24
5
25
15
6
16
7
17
8
18
19
9
10
20
If you like download this sample from GitHub.
I'm trying to find a way of causing the program to not pause but for their to be a delay to execute certain tasks. I.e. I am trying to delay outputting 'Hello' to the console for 10 seconds for example, but the program will continue to execute the rest of the program.
Using TPL:
static void Main(string[] args)
{
Console.WriteLine("Starting at " + DateTime.Now.ToString());
Task.Run(() =>
{
Thread.Sleep(10000);
Console.WriteLine("Done sleeping " + DateTime.Now.ToString());
});
Console.WriteLine("Press any Key...");
Console.ReadKey();
}
output:
Starting at 2/14/2017 3:05:09 PM
Press any Key...
Done sleeping 2/14/2017 3:05:19 PM
just note that if you press a key before 10 seconds, it will exit.
There are 2 typical ways to simulate a delay:
an asynchronous task-like: Task.Delay
or a blocking activity: Thread.Sleep
You seem to refer to the first situation.
Here it is an example
public static void Main(string[] args)
{
Both();
}
static void Both() {
var list = new Task [2];
list[0] = PauseAndWrite();
list[1] = WriteMore();
Task.WaitAll(list);
}
static async Task PauseAndWrite() {
await Task.Delay(2000);
Console.WriteLine("A !");
}
static async Task WriteMore() {
for(int i = 0; i<5; i++) {
await Task.Delay(500);
Console.WriteLine("B - " + i);
}
}
Output
B - 0
B - 1
B - 2
A !
B - 3
B - 4
Start a new thread:
Task.Factory.StartNew(new Action(() =>
{
Thread.Sleep(1000 * 10); // sleep for 10 seconds
Console.Write("Whatever");
}));
You could use a combination of Task.Delay and ContinueWith methods:
Task.Delay(10000).ContinueWith(_ => Console.WriteLine("Done"));
You could use 'Thread.Sleep(10000);'
See:
https://msdn.microsoft.com/en-us/library/d00bd51t(v=vs.110).aspx
I am trying to make a multithreading application. But the input is onely with one thread. But I try to make it with three threads. THis is the program:
class MyThread
{
public int Count;
public Thread Thrd;
public MyThread(string name)
{
Count = 0;
Thrd = new Thread(this.Run);
Thrd.Name = name;
Thrd.Start();
}
// Entry point of thread.
void Run()
{
Console.WriteLine(Thrd.Name + " starting.");
do
{
Thread.Sleep(500);
Console.WriteLine("In " + Thrd.Name +
", Count is " + Count);
Count++;
} while (Count < 10);
Console.WriteLine(Thrd.Name + " terminating.");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main thread starting.");
// Construct three threads.
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
while (true)
{
Console.Write(".");
Thread.Sleep(100);
if (mt1.Count < 10 && mt2.Count < 10 && mt3.Count < 10)
{
break;
}
Console.WriteLine("Main thread ending.");
}
//do
//{
// Console.Write(".");
// Thread.Sleep(100);
//}
//while (mt1.Count < 10 && mt2.Count < 10 && mt3.Count < 10);
//Console.WriteLine("Main thread ending.");
// Console.ReadKey();
}
}
But the output is: see image:
So it onely displays one thread. And not three threads.
THank you
This has to be the output:
Main thread starting.
.Child #1 starting.
Child #2 starting.
Child #3 starting.
....In Child #1, Count is 0
In Child #2, Count is 0
In Child #3, Count is 0
.....In Child #1, Count is 1
In Child #2, Count is 1
In Child #3, Count is 1
.....In Child #1, Count is 2
In Child #2, Count is 2
In Child #3, Count is 2
.....In Child #1, Count is 3
In Child #2, Count is 3
In Child #3, Count is 3
.....In Child #1, Count is 4
In Child #2, Count is 4
In Child #3, Count is 4
.....In Child #1, Count is 5
In Child #2, Count is 5
In Child #3, Count is 5
.....In Child #1, Count is 6
In Child #2, Count is 6
In Child #3, Count is 6
.....In Child #1, Count is 7
In Child #2, Count is 7
In Child #3, Count is 7
.....In Child #1, Count is 8
In Child #2, Count is 8
In Child #3, Count is 8
.....In Child #1, Count is 9
Child #1 terminating.
In Child #2, Count is 9
Child #2 terminating.
In Child #3, Count is 9
Child #3 terminating.
Main thread ending.
But if I do it like this:
static void Main(string[] args)
{
Console.WriteLine("Main thread starting.");
// Construct three threads.
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
//while (true)
//{
// Console.Write(".");
// Thread.Sleep(100);
// if (mt1.Count < 10 && mt2.Count < 10 && mt3.Count < 10)
// {
// break;
// }
// Console.WriteLine("Main thread ending.");
//}
do
{
Console.Write(".");
Thread.Sleep(100);
}
while (mt1.Count < 10 && mt2.Count < 10 && mt3.Count < 10);
Console.WriteLine("Main thread ending.");
Console.ReadKey();
}
It gives the same result.
If I do this:
Console.WriteLine("Main thread starting.");
// Construct three threads.
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
mt1.Thrd.Join();
mt2.Thrd.Join();
mt3.Thrd.Join();
do
{
Console.Write(".");
Thread.Sleep(100);
} while (mt1.Thrd.IsAlive && mt2.Thrd.IsAlive && mt3.Thrd.IsAlive);
Console.WriteLine("Main thread ending.");
Same result. Just one thread.
I try it like this:
static void Main(string[] args)
{
Console.WriteLine("Main thread starting.");
// Construct three threads.
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
mt1.Thrd.Join();
mt2.Thrd.Join();
mt3.Thrd.Join();
do
{
Console.Write(".");
Thread.Sleep(100);
} while (mt1.Count < 10 || mt2.Count < 10 || mt3.Count < 10);
Console.WriteLine("Main thread ending.");
But still the same result.
oh:
This worked for me!!
Console.WriteLine("Main thread starting.");
// Construct three threads.
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
mt1.Thrd.Join();
mt2.Thrd.Join();
mt3.Thrd.Join();
do
{
Console.Write(".");
Thread.Sleep(100);
} while (mt1.Thrd.IsAlive || mt2.Thrd.IsAlive || mt3.Thrd.IsAlive);
Console.WriteLine("Main thread ending.");
You're creating three classes. Each class creates a new thread which increments its own property. But you're exiting the console app if all of the numbers are less than 10. In other words, if any one of these reaches 10 before the others
while (mt1.Count < 10 && mt2.Count < 10 && mt3.Count < 10);
then the Main() will end. There's no guarantee that any one of those counts will reach 10 before that condition is checked, let alone all three of them. One of them could reach 10 before the others even start.
You would get closer to intended affect if you change it to this:
while (mt1.Count < 10 || mt2.Count < 10 || mt3.Count < 10);
In other words, if any one of them is less than 10, keep going. When they all reach 10, stop.
Something else you'll find (or already have) is that unless you're careful, multithreaded apps can behave in unpredictable, inconsistent ways. There's nothing more frustrating than a program that runs perfectly 99% of the time but then suddenly does something different, and then it works as expected again. Here's an example where you can test and see the output.
The if statement you have is incorrect and doesn't work at all. When I used the "while" version, your code works for me except that your strategy to detect when the threads have finished is buggy (perhaps a source of your issue even). Try this code and see if your problems go away. If not, then you might be running into issues locally with available memory/cpu/thread pools. Reboot your computer and try again :)
static void Main(string[] args)
{
Console.WriteLine("Main thread starting.");
MyThread mt1 = new MyThread("Child #1");
MyThread mt2 = new MyThread("Child #2");
MyThread mt3 = new MyThread("Child #3");
mt1.Thrd.Join();
mt2.Thrd.Join();
mt3.Thrd.Join();
Console.WriteLine("Main thread ending.");
}
I found the solution. See my post
I have 4 tasks to complete using multithreading concept.
and I have 4 Waitress.
How to assign the waitress that are free to handle either one of the task??
-I kept on getting duplicated data (For eg : 4 Thread doing the similar task)
-If i used lock, it locks 1 thread to do 4 tasks which is not wat i want
my code:
private void MTDemo()
{
String threadName = Thread.CurrentThread.Name;
while (true)
{
int numWaitingCustomer = 0;
Int32.TryParse(textBox1.Text, out numWaitingCustomer);
if (numWaitingCustomer > 0)
{
String takeOrderString = String.Format("Take order {0},{1}", threadName, numWaitingCustomer);
String serveMeal = String.Format("Serve meal {0},{1}",threadName, numWaitingCustomer);
String billCustomer = String.Format("Bill Customer {0},{1}", threadName, numWaitingCustomer);
String cleanTable = String.Format("Clean Table {0},{1}", threadName, numWaitingCustomer);
OutputMessage1(takeOrderString); Thread.Sleep(500);
OutputMessage1(serveMeal); Thread.Sleep(500);
OutputMessage1(billCustomer); Thread.Sleep(500);
OutputMessage1(cleanTable); Thread.Sleep(500);
numWaitingCustomer--;
SetControlPropertyValue(textBox1, "text", numWaitingCustomer.ToString());
}
}
}
Have each thread loop through the task list and complete the nth task, so waitress one will complete tasks 0,4,8... waitress 2 complete tasks 1,5,9... etc.
for(int i = threadNumber; i < taskList.length-threadNumber; i = i*totalThreads+ThreadNumber) {
...
}