3

Nope, this code doesn't respect the semaphore. It just send all emails without concurrency degree limiting by semaphore. Because return SendEmailAsync returns right after Task object is received not the method finished, then semaphore is released immediately. Thus semaphore thottles only requests creation which I assume is fast. The fix is await in try ...


2

Your approach can result in a huge number of tasks active at any given time, each of them representing load on the machine's IO resources. You need a way to limit the number of tasks. Your approach also abuses the Select() call pretty badly. If nothing else, it makes the code very hard to read. Here is a demonstration using a fixed number of tasks to ...


1

Yup. Looks like a queue. Maybe all multithreading is really a queue? ... strokes beard philosophically Naming: terminate() should probably be called finished() or done() or something similar. (To distance it from std::terminate). stop() would also be wrong, since that implies we're telling the threads to stop processing regardless of whether there's more ...


1

The usage of nextResetTime is incorrect. The non-locked accesses were under the assumption that those reads would be atomic; unfortunately, DateTimeOffset (and DateTime) are structs, value types. C# only provides atomicity guarantees for reference types and a subset of value types (which structs do not fall under). The two possible solutions here are to ...


Only top voted, non community-wiki answers of a minimum length are eligible