I 've the following code:
int counter = 1;
var lockTarget = new object();
Parallel.For(1, totalSIM, i => {
/* do some stuff */
lock(lockTarget) {
_printConcurrent(counter++);
}
});
and I need to call _printConcurrent
every ~200 times, not every time. I thought about do a MOD
(%) for counter
, but I can't understand how to use the condition. I enclosed the lock
in an if but I can't use the counter
so I'm in a logic loop instead the code :S
Any help will be appreciated.
_printConcurrent
is only an output of the process, I sacrifice some performance for monitoring data.
You could increment atomically the counter
without locking, with the Interlocked.Increment
method, and enter the lock
only if the result of the atomic increment is divisible by 200:
int counter = 0;
ParallelOptions options = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
Parallel.For(0, totalSIM, options, i => {
/* do some stuff */
int current = Interlocked.Increment(ref counter);
if (current % 200 == 0)
{
lock (options) _printConcurrent(current);
}
});
This way the _printConcurrent
will be called once every 200 iterations, without blocking the rest 199 iterations.
Update: The above approach has a minor flaw. It doesn't guarantee that the _printConcurrent
will be called sequentially with an incremented argument. For example it is theoretically possible that the _printConcurrent(400)
will be called before the _printConcurrent(200)
. That's because the operating system can suspend any thread at any time for a duration of around 10-30 milliseconds (demo), so a thread could be suspended immediately after the Interlocked.Increment
line, and lose the race to enter the lock
by a non-suspended thread. In case this is a problem, you can solve it be throwing a second counter in the mix, that is incremented only inside the lock
:
int counter1 = 0;
int counter2 = 0;
const int step = 200;
ParallelOptions options = new() { MaxDegreeOfParallelism = Environment.ProcessorCount };
Parallel.For(0, totalSIM, options, i => {
/* do some stuff */
if (Interlocked.Increment(ref counter1) % step == 0)
{
lock (options) _printConcurrent(counter2 += step);
}
});