i'm creating app, have 50x50 map. on map can add dots, new instances of class "dot". every dot has it's own thread, , every thread connected specific dot operates on method "explore" of class, , in method there method "check_place(x,y)" responsible checking if place on map discovered. if not, static variable of class "num_discovered" should incremented. single instance of method "check_place(x,y)" should accessed in real-time every thread started in app.
constructor:
public dot(form1 f) {         /...     thread = new system.threading.thread(new system.threading.threadstart(explore)); //wątek wykonujący metodę explore klasy robot     thread.start(); }   check_place(x,y) method:
static void check_place(int x, int y) {     lock (ob)     {         if (discovered[x, y] == false)         {             discovered[x, y] = true;             num_discovered += 1;         }     } }   in explore method i'm invoking method "check_place(x,y)" this:
dot.check_place(x, y);   is enough achieve situation in single time 1 dot can check if place discovered?
is enough achieve situation in single time 1 dot can check if place discovered?
yes. what's point?
if threads spending of time waiting on other threads, have gained being multi-threaded?
there 3 (sometimes overlapping) reasons spawn more threads:
- to make use of more 1 core @ same time: overall throughput increases.
 - to have work done while thread waiting on else (typically i/o file, db or network): overall throughput increases.
 - to respond user interaction while work being done: overall throughput decreases, feels faster user separately being reacted to.
 
here last doesn't apply.
if "checking" involved i/o second might apply, , strategy might make sense.
the first apply, because threads spending of time waiting on other threads, don't gain improvement in throughput.
indeed, because there overhead involved in setting threads , switching between them, code slower having 1 thread everything: if 1 thread can work @ time, have 1 thread!
so use of lock here correct in prevents corruption , errors, pointless in makes slow.
what this:
if real case involves i/o or other reasons why threads in fact spend of time out of each others' way, have fine.
otherwise you've got 2 options.
easy: use 1 thread. hard: have finer locking.
one way have finer locking double-checking:
static void check_place(int x, int y) {   if (!discovered[x, y])     lock (ob)       if (!discovered[x, y])       {         discovered[x, y] = true;         num_discovered += 1;       } }   now @ least threads skip past cases discovered[x, y] true without holding other threads.
this useful when thread going result @ end of locked period. still not enough here though, because it's going move on case fights lock again.
if our lookup of discovered thread-safe , thread-safety finely grained, make progress:
static void check_place(int x, int y) {   if (discovered.setiffalse(x, y))     interlocked.increment(ref num_discovered) }   so far though we've moved problem around; how make setiffalse thread-safe without using single lock , causing same problem?
there few approaches. use striped locks, or low-locking concurrent collections.
it seem have fixed-size structure of 50×50, in case isn't hard:
private class dotmap {   //ints because can't use interlocked bools   private int[][] _map = new int[50][];   public dotmap()   {     for(var = 0; != 50; ++i)       _map[i] = new int[50];   }   public bool setiffalse(int x, int y)   {     return interlocked.compareexchange(ref _map[x][y], 1, 0) == 0;   } }   now our advantages are:
- all of our locking lower-level (but note 
interlockedoperations still slow down in face of contention, albeit not aslock). - much of our locking out of way of other locking. specifically, in 
setiffalsecan allow separate areas checked without being in each others way @ all. 
this neither panacea though (such approaches still suffer in face of contention, , bring own costs) nor easy generalise other cases (changing setiffalse more check , change single value not easy). it's still quite on machine lot of cores slower single-threaded approach.
another possibility not have setiffalse thread-safe @ all, ensure threads each partitioned each other never going hit same values and structure safe in case of such multi-threaded access (fixed arrays of elements above machine word-size thread-safe when threads ever hit different indices, must mutable structures 1 can add and/or remove not).
in all, you've got right idea how use lock keep threads causing errors, , approach use 98% of time when lends multithreading because involves threads waiting on else. example though hits lock benefit multiple cores, , creating code not trivial.
Comments
Post a Comment