1

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.

6
  • What didn't work about the lock idea? If each account has its own lock, and every thread that operates on an account takes that account's lock and releases it when done there shouldn't be a problem. Please show more code. Commented Jun 27, 2016 at 16:22
  • 1
    Put the accounts into a stack, lock the stack of accounts when accessing it, pop an account from the stack when you want to use it, push it back when the task is completed. Commented Jun 27, 2016 at 16:39
  • @Great.And.Powerful.Oz not possible, assume the stack is empty and another action comes in that has to be executed. would I keep the lock on the stack? no, no other thread could put in an account anymore then. So I release the lock again and then what, retry after some time? I think solutions that are based on wait-retry are not that good :( Commented Jun 27, 2016 at 16:46
  • @Felheart, ok, how is that any different than a list where all the accounts are being used? Wait/retry is how accessing a limited resource is done, or you create a new account. And, yes when a thread is done with an account, it can indeed put it back if the wait/retry is coded correctly. This is a well-known problem and is exactly how thread pools work. Commented Jun 27, 2016 at 16:51
  • @Great.And.Powerful.Oz I assume you don't mean "wait for x milliseconds, then retry" by "wait-retry" but instead something more sophisticated like some event-thing that gets pulsed/notified as soon as an account is available again? So we don't actually wait for some fixed amount of time, but instead know when there's some change? Commented Jun 27, 2016 at 16:54

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

1 Comment

One queue for accounts, one for actions, and every account has another queue that contains the actions only this account can execute. So 3 queues in total. I'll do it that way thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.