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
interlocked
operations still slow down in face of contention, albeit not aslock
). - 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
Post a Comment