c# - Atomic wait-then-take operation on number -
i have following class:
public class atomiclong { private long initial; private long value; public atomiclong(long value = 0) { this.initial = value; this.value = value; } public class handle : idisposable { private atomiclong source; private long amount; public handle(atomiclong source, long amount) { this.source = source; this.amount = amount; } public void dispose() { if (source == null) return; interlocked.add(ref source.value, amount); source = null; } } public handle claim(long amount) { if (amount > initial) throw new argumentoutofrangeexception("amount", amount, "must no more initial amount."); if (amount < 0) throw new argumentoutofrangeexception("amount", amount, "must nonnegative."); while (true) { var oldvalue = interlocked.read(ref value); var newvalue = oldvalue - amount; if (newvalue >= 0 && oldvalue == interlocked.compareexchange(ref value, newvalue, oldvalue)) { return new handle(this, amount); } } } } an example usage of can have single atomiclong unusedmemory represents current number of bytes of memory available set of workers. (it's not meant anywhere near exact - it's rough measure.) on bunch of different worker threads:
while (true) { var unitofwork = waitforunitofwork(); long requiredmemory = unitofwork.requiredmemory; using (var handle = unusedmemory.claim(requiredmemory)) { //wait until requirememory can claimed unusedmemory //do work reserved memory, represented handle //when handle disposes, memory released unusedmemory } } the problem atomiclong class calls claim busy-wait until return. i'd fix using kind of os-level wait handle abstraction.
can suggest how go doing that?
motivation
consider following scenario:
- unusedmemory starts initial value of 10gb (
10 << 30) - 100 worker threads
- 10 units of work, each taking 10gb , 1 minute perform
- first worker calls
claim(10 << 30), nearly-immediately returns- it begins doing work finish after 1 minute
- some 9 other workers make identical call
claim(10 << 30), "bad" busy wait 1 minute- 9 threads doing
while(true){/*do nothing*/}loop inclaimmethod! - lots of needless cpu usage
- 9 threads doing
- the rest of workers (90) "good" os-level wait in
waitforunitofwork()method
the important point: claim "cheap" if requested amount of memory available claimed. if isn't, busy-waiting happens until available.
just entirely clear, in claim method, i'm pointing out exact expression makes difference (newvalue >= 0):
while (true) { var oldvalue = interlocked.read(ref value); var newvalue = oldvalue - amount; if (newvalue >= 0 && // <--------------------------- problem oldvalue == interlocked.compareexchange(ref value, newvalue, oldvalue)) { return new handle(this, amount); } } the question not whether interlocked.compareexchange going expensive - i'm aware it's cheap. question how deal busy-waiting occurs in case when amount caller wants claim greater amount in atomiclong.
if have different approach solving kind of problem, or see flaw in have, i'd hear too!
you have several options.
for instance, can create smarter busy-wait, putting active thread sleep given time interval, doesn't check condition, periodically.
another solution create custom event , wait event in active thread, , can define custom event fulfill task believe.
you can read more events here. can read custom event creation here.
Comments
Post a Comment