c# - Threads operating on the one instance of a method -


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:

  1. to make use of more 1 core @ same time: overall throughput increases.
  2. to have work done while thread waiting on else (typically i/o file, db or network): overall throughput increases.
  3. 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:

  1. all of our locking lower-level (but note interlocked operations still slow down in face of contention, albeit not as lock).
  2. much of our locking out of way of other locking. specifically, in setiffalse can 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