c # – Repeat a task that may fail

Almost like this question here, I am playing with some methods that may fail, but in my case, the method that fails is not an exceptional case; it just means that I need to try to run it again.

The method I'm writing is inherently stochastic, so running it several times produces different results. Some are valid, others are invalid.

As in the other question, I created a class that represents a successful / unsuccessful execution.

public structure read-only maybe {

public readonly bool ContainsValue;
public reading T value only;

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    Maybe public (bool contains value, value T) {
ContainsValue = containsValue;
Value = value;
}

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    maybe public static Only (value of t) {
back again Maybe(
ContainsValue: true,
value: value);
}

maybe public static Empty {obtain; } = new Maybe(
ContainsValue: false,
Default value
);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public implicit static operator(Value T) => Maybe.Just (value);
}

// This class is used only to make the syntax of Maybe cleaner
public static class Maybe {

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    maybe public static Single(Value T) => Maybe.Just (value);
}

At the end of my method, I can only check if the result is valid and return Maybe.Just (Result) or Maybe.Empty () if it is not.

Review the questions about Maybe and Maybe:

  • Is this structure okay? I opted for a structure to reduce allocations. I do not intend to store references to it; Just return it, verify the results and forget it.
  • Is it the creation of a non-generic class just to enable a more beautiful legitimate syntax? I'd rather write Maybe.Just (whatever) than Maybe.Just (whatever)

Then I realized that I tend to wrap my "test methods" inside a loop … So I "raised" the code to a different class:

Public static class ProcessRetrier {

maybe public static run(int maximumRetries, Func <Maybe> func) {
if (maximumRetries < 0)
            throw new ArgumentOutOfRangeException(nameof(maximumRetries) + " must be >= 0 ");
if (func == null)
throws the new exception ArgumentNullException (nameof (func));

for (int i = 0; i <= maximumRetries; i ++) {
result var = func ();

if (result.ContainsValue)
return result
}

maybe go back.Empty;
}
}

Review question about ProcessRetrier

  • Is this class design legitimate?
  • Do you guys have any suggestions?

Finally, I decided it would be great if I could execute the different attempts on different threads, so I created this monstrosity here:

maybe public static RunParallel(int maximumRetries, Func <Maybe> func) {
if (maximumRetries < 0)
        throw new ArgumentOutOfRangeException(nameof(maximumRetries) + " must be >= 0 ");
if (func == null)
throws the new exception ArgumentNullException (nameof (func));

the attempts of var = 0;

var tasks = new task <maybe>[Environment.ProcessorCount];
var ended = 0;

for (int i = 0; i < tasks.Length; i++) {
        tasks[i] = Task.Run(() => {
while (true) {
if (retries> = maximumRetries || terminated> 0)
maybe go back.Empty;

attempt of var = func ();
if (try.ContainsValue) {
Interlock. Increase (ref finished);
return attempt
} else {
Interlock. Increase (ref attempts);
}
}
});
}

Task.WaitAny (tasks);

foreach (var t in tasks) {
if (t.Result.ContainsValue)
returns t.Result;
}

maybe go back.Empty;
}

And now it's the meat of the problem:

  • Is this parallel implementation correct?
  • When lambda "swallows" retries Y finishedAre the different threads seeing the same values? Or each task will try maximumRetries?
  • If each thread task is reading / modifying its own copy of retriesHow can I make everyone use the same value?