Riki
Riki

Reputation: 1806

Locking any of multiple locks

I have a pool of "accounts". Each one can only be used by one thread at a time. So at first I thought that a simple lock should suffice. But it turned out that that won't work easily.

The only idea this would work would be to use Monitor.TryEnter with an timeout of 0 and then keep looping over the objects forever until at some point I successfully lock onto an account, then use it.

This is obviously not very easy on the computers resources and generally bad style.

My next Idea was to give each object a queue of actions like this List<Action<Account> queue but somehow that doesn't seem very elegant either.

The actions I do on the accounts are async Task as well so that makes everything even more complex. (Having to use Nito.AsyncEx instead of normal lock())

Usually I do not care about what account I work with as long as my action is executed. So I work with the first account that's available at the moment. But sometimes I even want to operate on a specific account as well.

How should I design my "AccountPool" so I can easily have methods like ExecuteOnFirstUnusedAccount(Action<Account> action) and ExecuteOnSpecificAccount(Func<Account,bool> filter, Action<Account> action) ?

edit: One possible solution I just thought of would be the following.

Each account has its own Task (or Thread, doesn't matter). Then there's a single (global) BlockingCollection<Action<Account>> and each of those Tasks then calls .Take() on the collection.

The problem with that: When I need to have one specific Account execute some action that's not possible anymore since they all wait for the blocking collection.

Upvotes: 1

Views: 53

Answers (1)

Alexei Kaigorodov
Alexei Kaigorodov

Reputation: 13515

Imagine a taxi stand. When there is no passengers, taxi cabs form a queue. When there is no taxi, passengers form another queue. Account is like a taxi, and actions like customers. This way ExecuteOnFirstUnusedAccount is implemented. ExecuteOnSpecificAccount needs little more work. For each specific account. create a queue for actions. After an action is put in the queue, check if the specific account is in the main account queue. if so, extract it from there and submit it to a processor. It then executes all the actions from its own queue and finally return itself to the main queue.

Both operations require locking of the whole queue pool.

Upvotes: 1

Related Questions