I was trying out a code sample from this book that should demonstrate that the post decrement operator is not atomic. The code is as I have entered it into LinqPad.
void Main() {
var count = 0;
do {
_x = 10000;
for (int i = 0; i < 100; i++) {
new Thread(Go).Start();
}
Thread.Sleep(1000);
Console.WriteLine("Try "+ count);
count++;
} while (_x == 0);
Console.WriteLine(_x);
}
int _x = 10000;
void Go() { for (int i = 0; i < 100; i++) _x--; }
The idea is that decrementing _x in parallel on multiple threads without locking may lead to a value of _x other then 0 when all the threads have finished.
My problem is that no matter how long I seem to try I always get 0 as a result.
I have run the code on two different computers (both Windows 7) and two different versions of .NET and both give me the same result.
What am I missing here?
I have added 100000 interations in Go as Lasse V. Karlsen has suggested. The code now works as expected on the first try. I have also moved the Thread creation out of the loop and reduced the thread count as Henk Holterman has suggested.
void Main()
{
var count = 0;
do {
_x = 1000000;
var threads = Enumerable.Range(0,10).Select (_ => new Thread(Go)).ToList();
foreach (var t in threads)
{
t.Start();
}
Thread.Sleep(1000);
Console.WriteLine("Try "+ count);
count++;
} while (_x == 0);
Console.WriteLine(_x);
}
int _x;
void Go() { for (int i = 0; i < 100000; i++) _x--; }
The code now works as expected.
Related
static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
int noOfThreads = Environment.ProcessorCount;
//int minVal = 1;
int maxVal = 10000000;
int blockSize = maxVal / noOfThreads;
List<Thread> threads = new List<Thread>();
List<List<int>> results = new List<List<int>>();
object thisLock = new object();
for (int i = 0; i < noOfThreads; ++i)
{
lock(thisLock)
{
Thread th = new Thread(() =>
{
results.Add(GetPrimeNumbers(i * blockSize, i * blockSize + blockSize));
});
th.Start();
threads.Add(th);
}
}
foreach (var elem in threads)
elem.Join();
}
private static List<int> GetPrimeNumbers(int low, int high)
{
List<int> result = new List<int>();
//Debug.WriteLine("Low: {0}. High: {1}", low, high);
for(int i = low; i <= high; ++i)
{
if (IsPrime(i))
result.Add(i);
}
return result;
}
static bool IsPrime(int number)
{
if (number % 2 == 0)
return false;
else
{
var topLimit = (int)Math.Sqrt(number);
for (int i = 3; i <= topLimit; i += 2)
if (number % i == 0)
return false;
return true;
}
}
With the above code, I was expecting that when I put breakpoint in the GetPrimeNumbers(int low, int high) I would see range of values for low and high, e.g: (0, 1250000), (1250000, 2500000).....(8750000, 10000000). But what I observing is that there are certain blocks that gets passed multiple times - (2500000, 3750000) while certain do not passed at all -(0, 1250000) and this behaviour also matches the results I am getting.
I am curious why I am seeing this behaviour. Is there a way to prevent this?
I am aware of the fact that I can use Parallel.For() and over here I do see the expected behaviour at breakpoint in GetPrimes(int low, int high). But as I mentioned before I am curious why I am seeing the former behaviour.
Thanks in advance!
The problem is that a for loop reuses the same i variable across iterations, and your thread delegate is closing over that variable.
There are various ways to fix this. A simple one is to use a new variable declared within your loop:
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
lock(thisLock)
{
Thread th = new Thread(() =>
{
results.Add(GetPrimeNumbers(j * blockSize, j * blockSize + blockSize));
});
th.Start();
threads.Add(th);
}
}
This still has other issues, though. I'd recommend something more like this:
var allPrimeNumbers = Enumerable.Range(0, numberOfThreads)
.AsParallel()
.SelectMany(i => GetPrimeNumbers(i * blockSize, i * blockSize + blockSize))
.ToList();
Further Reading
Is there a reason for C#'s reuse of the variable in a foreach?
StriplingWarrior had it close, but as mentioned in the comments, you still have a threading bug. You need to move the lock inside the Thread action. Also, to get the best performance, hold the lock for the shortest amount of time possible, which is when modifying the shared results variable. To do that I separated the GetPrimeNumbers call from the results.Add call.
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
Thread th = new Thread(() =>
{
result = GetPrimeNumbers(j * blockSize, j * blockSize + blockSize);
lock(thisLock)
{
results.Add(result);
}
});
th.Start();
threads.Add(th);
}
Also, unless you really need to manage your own threads I would recommend using Tasks (TPL) instead. Here is a modification using Tasks
Task<List<int>> tasks = new Task<List<int>>();
for (int i = 0; i < noOfThreads; ++i)
{
int j = i; // capture the value
tasks.Add(Task.Run(() => GetPrimeNumbers(j * blockSize, j * blockSize + blockSize)));
}
Task.WaitAll(tasks);
results = tasks.Select(t => t.Result).ToList();
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;
}
How can I dequeue all values in a Queue? In the following code when I try to do so loop stops in the middle. I don't understand.
Queue<int> integers = new Queue<int>();
for (int i = 0; i < 20; i++)
{
integers.Enqueue(i);
}
Console.WriteLine(integers.Count); // 20
Console.WriteLine();
for (int i = 0; i < integers.Count; i++)
{
Console.WriteLine(integers.Dequeue()); // Stops at 10
}
Console.WriteLine();
Console.WriteLine(integers.Count); // 10
Your integers.Count is decreasing every time you dequeue, so after ten iterations of your for loop, it will be at 10, so the loop will exit.
For your code to work, just save the length of your queue before the loop, like so:
var length = integers.Count;
for (int i = 0; i < length; i++)
{
Console.WriteLine(integers.Dequeue());
}
edit: Above solution is with minimal changes to OP's code. As per suggestions in the comments (and other answers), a while loop is generally more recommended for this type of task:
while (integers.Count != 0) {
Console.WriteLine(integers.Dequeue());
}
Just change the loop to be:
while(integers.Count > 0) { Console.WriteLine(integers.Dequeue()); }
You are removing items from queue when you dequeue.
Try this: https://dotnetfiddle.net/FbXgoA
Queue<int> integers = new Queue<int>();
for (int i = 0; i < 20; i++)
{
integers.Enqueue(i);
}
Console.WriteLine(integers.Count); // 20
Console.WriteLine();
while(integers.Count > 0)
{
Console.WriteLine(integers.Count + ": " + integers.Dequeue());
}
Console.WriteLine();
Console.WriteLine(integers.Count); // 0
The issue is that as you dequeue the integers, integers.Count is also updated at the same time.
Thus, by the middle of the queue, i = 10 and also integers.Count = 10, so the for loop exits.
Try this:
while (integers.Count > 0)
{
Console.WriteLine(integers.Dequeue());
}
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
I tried to check a perfomance with boxing and without.
Here is a code:
public struct p1
{
int x, y;
public p1(int i)
{
x = y = i;
}
}
public class MainClass
{
public static void Main()
{
var al = new List<object>();
var l = new List<p1>();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
al.Add(new p1(i));
}
p1 b;
for (int i = 0; i < 1000; i++)
{
b = (p1)al[i];
}
Console.WriteLine(sw.ElapsedTicks);
var time = sw.ElapsedTicks;
for (int i = 0; i < 1000; i++)
{
l.Add(new p1(i));
}
p1 v;
for (int i = 0; i < 1000; i++)
{
v = l[i];
}
var t = sw.ElapsedTicks - time;
Console.WriteLine(t);
Console.ReadKey();
}
}
But List of object works faster then List of p1. Why?
1139
9256
1044
6909
I suspect this could be caused by quite a few things.
First, you should always put timings like this into a loop, and run them more than once in the same process. The JIT overhead will occur on the first run, and can dominate your timings. This will skew the results. (Normally, you'll want to completely ignore the first run...)
Also, make sure that you're running this in a release build, run outside of the Visual Studio test host. (Don't hit F5 - use Ctrl+F5 or run from outside VS.) Otherwise, the test host will disable most optimizations and dramatically slow down your results.
For example, try the following:
public static void Main()
{
for (int run = 0; run < 4; ++run)
{
if (run != 0)
{
// Ignore first run
Console.WriteLine("Run {0}", run);
}
var al = new List<object>();
var l = new List<p1>();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
al.Add(new p1(i));
}
p1 b;
for (int i = 0; i < 1000; i++)
{
b = (p1)al[i];
}
sw.Stop();
if (run != 0)
{
// Ignore first run
Console.WriteLine("With boxing: {0}", sw.ElapsedTicks);
}
sw.Reset();
sw.Start();
for (int i = 0; i < 1000; i++)
{
l.Add(new p1(i));
}
p1 v;
for (int i = 0; i < 1000; i++)
{
v = l[i];
}
sw.Stop();
if (run != 0)
{
// Ignore first run
Console.WriteLine("Without boxing: {0}", sw.ElapsedTicks);
}
}
Console.ReadKey();
}
On my system, by ignoring the first run (JIT issues), and running outside the VS test host in release, I get:
Run 1
With boxing: 99
Without boxing: 61
Run 2
With boxing: 92
Without boxing: 56
Run 3
With boxing: 97
Without boxing: 54
This is obviously dramatically better with the generic, non-boxed version.
Given the very large numbers in your results - I suspect this test was run in VS in Debug mode...
Structs are passed by value not reference. When you auto-box it I believe it will then be passed around by reference. So it is copied multiple times in the second loop.