-1

Pretty simple question:

int retryAttempts = 3;

retry:
try {
    await getSemaphore();
    throw new Exception();
}
catch {
    if (0 > retryAttempts--) {
        await Task.Delay(5000);
        goto retry;
    }

    return;
}
finally {
    releaseSemaphore();
}

In this example, will the semaphore be released one or three times?

André Reichelt
  • 1,484
  • 18
  • 52
  • 2
    Add a log/breakpoint in `releaseSemaphore` and see what happens? – Camilo Terevinto Jan 31 '22 at 15:34
  • @CamiloTerevinto I want to know what the expected/defined behavior should be. – André Reichelt Jan 31 '22 at 15:35
  • Looks like an interview question that you want to get the answer to. Debug the code, the outcome will be the same every time – Camilo Terevinto Jan 31 '22 at 15:37
  • @CamiloTerevinto It's not an interview question. It's a bug in my software. The code sporadically is running extremely slow and I have a feeling that it has something to do with timeouts and unreleased semaphores. I can't simply put a breakpoint there, because, as I mentioned, the error happens sporadically. This is just a minimal example. The actual code has about 1000 lines. – André Reichelt Jan 31 '22 at 15:41
  • 3
    Look it up in the [C# language specification](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/statements#12104-the-goto-statement). The behaviour is clearly stated there: yes, the finally block is executed. – Klaus Gütter Jan 31 '22 at 15:42
  • @KlausGütter I know, that the block **is** executed, but I want to know if it is executed only once (after leaving the block altogether), of after each `goto`. – André Reichelt Jan 31 '22 at 15:45
  • 1
    @AndréReichelt No, the definition is extremely clear: "If the goto statement exits one or more try blocks with associated finally blocks, **control is initially transferred to the finally block of the innermost try statement**." – Camilo Terevinto Jan 31 '22 at 15:48
  • the best practice about `goto`: **don't** - you should try a loop instead (as most simple implementation), or a framework built for exception recovery. – Franz Gleichmann Jan 31 '22 at 15:53

2 Answers2

4

finally will execute every time you leave the catch block. So in your case releaseSemaphore() will be called three times (after each goto).

I also invite you to read the official documentation about try-finally here

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
Abdelkrim
  • 1,083
  • 8
  • 18
1

The C# specification (ECMA-334) states as follows:

A goto statement is executed as follows:

  • If the goto statement exits one or more try blocks with associated finally blocks, control is initially transferred to the finally block of the innermost try statement. When and if control reaches the end point of a finally block, control is transferred to the finally block of the next enclosing try statement. This process is repeated until the finally blocks of all intervening try statements have been executed.

  • Control is transferred to the target of the goto statement.

So the goto only happens after all relevant finally blocks have executed.

Charlieface
  • 52,284
  • 6
  • 19
  • 43