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 in claim method!
    • lots of needless cpu usage
  • 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

Popular posts from this blog

blackberry 10 - how to add multiple markers on the google map just by url? -

php - guestbook returning database data to flash -

delphi - Dynamic file type icon -