c# - Implementing a pool with a time limit -
continuing question:
correct way implement resource pool
i'm thinking implementing maximum amount of time user of pool allowed continue hold on object pool, i'm not sure of right way implement such thing. so, have this:
ifoo getfoofrompool() { if (_sem.wait(waittimeout)) { return pop(); } throw new waittimeoutexception("timed out waiting foo instance"); }
so _sem
semaphore , pop
pop off instance stack (initializing if needed), far good.
when caller done ifoo
, return stack so:
void releasefoo(ifoo p) { if (p == null) { throw new argumentnullexception("foo parameter null"); } push(p); _sem.release(); }
and wrap wrapper class using idisposable
ensure foo
gets returned pool. client side, looks this:
using (var f = mypool.getdisposablefoo()) { // stuff... }
what i'd have such if // stuff
takes long (or hangs), ifoo
recycled , calling code throw exception.
so thought of doing this:
private ifoo pop() { ifoo p; _stack.trypop(out p); if (p == null) { p = runfactory(); // lazy initialization of stack } if (maximumloantime > 0) { p.currenttoken = new cancellationtokensource(); task.delay(maximumloantime, p.currenttoken.token).continuewith(() => { // timeout, return stack // inform current owner??? push(p); }); } return p; }
the problem how make sure current holder gets signaled doesn't continue try , use instance of ifoo
might in use else.
so ended adding loanexpired
event , onloanexpired
method ifoo
. works this:
private ifoo pop() { ifoo p; _stack.trypop(out p); if (p == null) { p = runfactory(); // lazy initialization of stack } if (maximumloantime > 0) { p.currenttoken = new cancellationtokensource(); task.delay(maximumloantime, p.currenttoken.token).continuewith(() => { p.currenttoken.dispose(); p.onloanexpired(); }, taskcontinuationoptions.notoncanceled); } return p; }
returning expired loan object deferred foowrapper
subscribes loanexpired
event of foo
instance it's wrapping:
private void foo_loanexpired(object sender, eventargs e) { isdisposed = true; // checked on attempt use object foo.loanexpired -= foo_loanexpired; _pool.returnexpiredloan(foo); onloanexpired(); // pass event client handlers }
and in pool, returnexpiredloan
looks this:
void returnexpiredloan(ifoo p) { // since it's expired, there risk broken or hung // push null on stack force fresh instance next time around _stack.push(null); _sem.release(); p.dispose(); }
now made decision dump expired foo
, create new 1 in particular case, wouldn't right approach different resource.
and couple of other changes, when foowrapper
disposed, have unsubscribe event handler:
public void dispose() { foo.loanexpired -= foo_loanexpired; if (!isdisposed) // don't try , return instance if killed { _pool.releasefoo(foo); } }
and when push foo
on stack, need cancel expiration , dispose token source:
private void push(ifoo p) { if (p.currenttoken != null) { p.currenttoken.cancel(); p.currenttoken.dispose(); p.currenttoken = null; } _stack.push(p); }
Comments
Post a Comment