Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
It's giving me build error (i am using vs 2017), but in error list there is no error found
public static async void Main(string[] args)
{
await LongOP1();
}
public static async Task LongOP1()
{
long x = 0;
await Task.Run(() =>
{
for (int i = 0; i <= 10000; i++)
{
for (int j = 0; j <= 10000; j++)
{
x += i + j;
}
}
});
}
You cannot use the async keyword on the Main method yet.
See this for an alternative, and look at other answers in the thread for an explanation :
https://stackoverflow.com/a/24601591/4587181
Relevant code :
static void Main(string[] args)
{
Task.Run(async () =>
{
// Do any async anything you need here without worry
}).GetAwaiter().GetResult();
}
I prefer to do it this way
public static void Main()
{
Task t = LongOP1();
// Do other stuff here...
t.Wait();
}
public static async Task LongOP1()
{
long x = 0;
await Task.Run(() =>
{
for (int i = 0; i <= 10000; i++)
{
for (int j = 0; j <= 10000; j++)
{
x += i + j;
}
}
});
}
Related
I have a Func like this:
int loopMax = 10, taskMax = 10;
int executionCounter = 0;
Func<int> calculator = new Func<int>(() =>
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
result = 0;
result += i;
}
return result;
});
Which could be called by multiple threads. For example like this:
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _=calculator());
}
Task.WaitAll(tasks);
I need to share the calculator function across all threads, and makes this function being called only once. In fact the executionCounter variable's value after running this code should remain 1, and all of the threads should have the same return value.
UPDATE 1
I think I can solve it if I find a way to server the first thread and block every other threads and after completion of first thread's method call, signal the methods result to other threads and also cancel them, to prevent them calling calculator again.
Using lock inside the method also is not what I am looking for, because in that case again the calculator is being called multiple times...
It seems that you need the Lazy<T> class. This class provides support for lazy initialization. Here is how you could use it:
Lazy<int> lazyCalculator = new Lazy<int>(calculator);
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = lazyCalculator.Value);
}
Task.WaitAll(tasks);
When a Lazy instance is constructed, it can take an optional LazyThreadSafetyMode argument. The default value of this argument is ExecutionAndPublication, with the behavior described below:
Locks are used to ensure that only a single thread can initialize a Lazy<T> instance in a thread-safe manner.
It looks like you want is that your Calculator method can be executed by any thread, but this method should be executed only once. If it is true, then we would use lock statement.
The purpose of lock statement is:
The lock statement acquires the mutual-exclusion lock for a given
object, executes a statement block, and then releases the lock
An example:
static object lockCalculatorMethod = new object();
static int executionCounter = 0;
static int loopMax = 10;
static int taskMax = 10;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() => _ = Calculator());
}
Task.WhenAll(tasks);
}
and Calculator method:
static int Calculator()
{
lock (lockCalculatorMethod)
{
if (executionCounter < 1)
{
executionCounter++;
int result = 0;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
if (result + i >= int.MaxValue)
{
result = 0;
result += i;
}
}
return result;
}
else
return -1;
}
}
UPDATE:
If you want to cache result and avoid recalculation while calling by other threads, then you can use threadSafe collection ConcurrentQueue<T> and just get items from this collection:
static object lockCalculatorMethod = new object();
static ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
static int executionCounter = 0;
static int loopMax = 7;
static int taskMax = 7;
static void Main(string[] args)
{
Task[] tasks = new Task[taskMax];
for (int i = 0; i < taskMax; i++)
{
tasks[i] = Task.Run(() =>
{
var result = Calculator();
Console.WriteLine(result);
});
}
Task.WaitAll(tasks);
}
And Calculator method:
static int Calculator()
{
int result = 0;
lock (lockCalculatorMethod)
{
int lockResult = 0;
if (executionCounter < 1)
{
executionCounter++;
for (int i = 0; i < loopMax; i++)
{
Thread.Sleep(100);
lockResult += i;
}
queue.Enqueue(lockResult);
}
}
queue.TryPeek(out result);
return result;
}
This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 11 months ago.
My program is running tasks in groups of n tasks at once each time.
Each task writes data to a Queue<string> object of his own, provided by an index to a Queue<string> in a List<Queue<string>> of queues.
the tasks do not share data or Queues, yet I still get synchronization errors.
I know the data structures are not Thread-Safe, I don't understand why they should be, and why I get the errors, since each Task has his own data structure, what could cause the errors?
here is a simple code to demonstrate:
class Program
{
static int j = 0;
List<Queue<string>> queueList = new List<Queue<string>>();
public void StartTasts(int n)
{
for (int i = 0; i < n; i++)
queueList.Add(new Queue<string>());
List<Task> tsk = new List<Task>();
for (int TaskGroup = 0; TaskGroup < 10; TaskGroup++)
{ //10 groups of task
//each group has 'n' tasks working in parallel
for (int i = 0; i < n; i++)
{
//each task gets its own and independent queue from the list
tsk.Add(Task.Factory.StartNew(() =>
{
DoWork(j % n);
}));
j++;
}
//waiting for each task group to finish
foreach (Task t in tsk)
t.Wait();
//after they all finished working with the queues, clear queues
//making them ready for the nest task group
foreach (Queue<string> q in queueList)
q.Clear();
}
}
public void DoWork(int queue)
{
//demonstration of generating strings
//and put them in the correct queue
for (int k = 0; k < 10000; k++)
queueList[queue].Enqueue(k + "");
}
static void Main(string[] args)
{
new Program().StartTasts(10);
}
}
this program generate some errors such as:
System.ArgumentException: 'Destination array was not long enough. Check destIndex and length, and the array's lower bounds.'
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' (at the Queue)
System.AggregateException: One or more errors occurred. ---> System.ArgumentException: Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
and more errors and would not come up on a Serial case.
I would love to understand why because I cant see how these tasks mess up each other's independent Queues.
The problem is normal variable closure issues. Because all tasks share the same instance of the variable j they will all share the same value, most likely what is happening is your loop starts up 10 tasks super quick, but before any of them can get to j % n the value of j has already become 10.
Make a local copy of k that is declared within the scope of the for loop and it should solve your problem.
public void StartTasts(int n)
{
for (int i = 0; i < n; i++)
queueList.Add(new Queue<string>());
List<Task> tsk = new List<Task>();
for (int TaskGroup = 0; TaskGroup < 10; TaskGroup++)
{ //10 groups of task
//each group has 'n' tasks working in parallel
for (int i = 0; i < n; i++)
{
int k = j; // `int k = i;` would work here too and give you the same results.
tsk.Add(Task.Factory.StartNew(() =>
{
DoWork(k % n);
}));
j++;
}
//waiting for each task group to finish
foreach (Task t in tsk)
t.Wait();
//after they all finished working with the queues, clear queues
//making them ready for the nest task group
foreach (Queue<string> q in queueList)
q.Clear();
}
}
If you want to see the problem in action with a simpler recreation, try this simple code instead.
public static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
int j = i;
Task.TaskFactory.StartNew(() =>
{
Thread.Sleep(10); //Give a little time for the for loop to complete.
Console.WriteLine("i: " + i + " j: " + j);
}
});
Console.ReadLine();
}
You have calculated the taskId inside of the task and changed the base for the calculation outside of the task.
I have changed the logic only slightly. I have not had any errors.
namespace Project1
{
using System.Collections.Generic;
using System.Threading.Tasks;
internal class Program
{
private static int j = 0;
private readonly List<Queue<string>> queueList = new List<Queue<string>>();
public void StartTasts(int n)
{
for (var i = 0; i < n; i++)
{
this.queueList.Add(new Queue<string>());
}
var taskList = new List<Task>();
for (var taskGroup = 0; taskGroup < 10; taskGroup++)
{
// 10 groups of task
// each group has 'n' tasks working in parallel
for (var i = 0; i < n; i++)
{
// each task gets its own and independent queue from the list
var taskId = j % n;
taskList.Add(
Task.Factory.StartNew(
() =>
{
this.DoWork(taskId);
}));
j++;
}
// waiting for each task group to finish
foreach (var t in taskList)
{
t.Wait();
}
// after they all finished working with the queues, clear queues
// making them ready for the nest task group
foreach (var q in this.queueList)
{
q.Clear();
}
}
}
public void DoWork(int queue)
{
// demonstration of generating strings
// and put them in the correct queue
for (var k = 0; k < 10000; k++)
{
this.queueList[queue].Enqueue(k + string.Empty);
}
}
private static void Main(string[] args)
{
new Program().StartTasts(10);
}
}
}
I do not think you problem is in the que, it seems like it in the list itself might be an issue.
As the rule of using parallel or synchronous processes the list is not a thread save DS.
Try using the thread save DS Like ConcurrentBag Class
This question already has an answer here:
Only last task runs!
(1 answer)
Closed 6 years ago.
I am trying to understand how I might be able to make better use of the .Net 4.5 TPL. Traditionally I used to manage the threads the old-school way, queueing and managing the threads directly.
I have created a silly program to explore the TPL, however, the code only seems to execute the last of the tasks added to my tasks list - I cannot determine why:
class Program {
static void Main(string[] args) {
var a = new A();
var b = new B();
var tasks = new List<Task<string>>();
for (int j = 33; j < 64; j++) {
tasks.Add(Task.Run(() => a.Go(j, 20)).ContinueWith((i) => b.Do(i)));
}
var finalTask = Task.Factory.ContinueWhenAll(tasks.ToArray(), r => {
foreach (var t in r)
Console.Write(t.Result);
});
finalTask.Wait();
Console.WriteLine("Finished.");
Console.ReadLine();
}
}
public class A {
public int Go(int chr, int loops) {
for (int i = 0; i < loops; i++) {
Thread.Sleep(10);
Console.Write((char)chr);
}
return loops;
}
}
public class B {
public string Do(Task<int> value) {
string s = "";
for (int i = 0; i < value.Result; i++) {
s = s + "a";
}
return s;
}
}
Any ideas why the other threads do not execute?
You have to capture the running variable j within the closure context:
for (int j = 33; j < 64; j++) {
var num = j;
tasks.Add(Task.Run(() => a.Go(num, 20)).ContinueWith((i) => b.Do(i)));
}
See also Captured variable in a loop in C#
I just tried this and it failed
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{
writeFile();
});
}
TextWriter myWriter = new StreamWriter("deneme.txt");
void writeFile()
{
for (int k = 0; k < 10000; k++)
{
int irTempPara = k;
Task.Factory.StartNew(() =>
{
writeFileForReal(irTempPara);
});
System.Threading.Thread.Sleep(10);
}
}
void writeFileForReal(int srParameter)
{
for (int k = 0; k < 999999999; k++)
{
myWriter.WriteLineAsync(srParameter + "_" + k);
}
}
It is c# 4.5 WPF application
So what method would you suggest for writing lines to a text file most effeciently and multi threading
How about this?
TextWriter.Synchronized(myWriter).WriteLine("Hello World!!!");
You can just use simple TPL way as you do, but you can set:
void writeFile()
{
for (int k = 0; k < 10000; k++)
{
int irTempPara = k;
Task.Factory.StartNew(() =>
{
writeFileForReal(irTempPara);
}, TaskCreationOptions.LongRunning); // this way you do not need sleep
// System.Threading.Thread.Sleep(10);
}
}
http://coderkarl.wordpress.com/2012/12/13/long-running-tasks-and-threads/
You must never rely on Sleep for synchronization in multi threading. Instead, take in consideration to use a synchronization mechanism such as a semaphore or a mutex.
I got confused in task class in c#. I want to know what is the equivalent line of my thread code of c# to task?
static void Main(string[] args)
{
int i = 3;
for (int x = 1; x <= i; x++)
{
Thread t = new Thread(RunThread);
t.Start();
}
Console.ReadLine();
}
public static void RunThread()
{
Console.WriteLine("Thread..");
}
Try
for (int x = 1; x <= i; x++)
{
Task.Factory.StartNew(RunThread);
}