Permalink
Browse files

Fix the read/write lock system to not starve the writer, simplifiy th…

…e interface. Fix a race condition on the node count, needed to switch from uint64_t to uword since uint64_t doesn't have atomic ops on 32bit machines.
  • Loading branch information...
1 parent a31ecd4 commit 3b07ddf578b0bace8615c5d6771ea263bf47dcbe @tewalds committed Jul 24, 2010
Showing with 86 additions and 33 deletions.
  1. +4 −9 player.cpp
  2. +73 −17 player.h
  3. +9 −7 playeruct.cpp
View
@@ -27,17 +27,12 @@ Move Player::genmove(double time, int maxruns, uint64_t memlimit){
//let them run!
if(!ponder)
- lock.unlock(); //remove the write lock
-
- cond.lock(); //lock the signal that defines the end condition
- cond.wait(); //wait a signal to end (could be from the timer)
- cond.unlock();
+ sync.unlock(); //remove the write lock
+
+ sync.wait(); //wait for the timer or solved
if(!ponder)
- lock.wrlock(); //stop the runners
- //maybe let them run again after making the move?
-
-
+ sync.wrlock(); //stop the runners
//return the best one
Node * ret = return_move(& root, rootboard.toplay());
View
@@ -2,17 +2,16 @@
#ifndef __PLAYER_H_
#define __PLAYER_H_
-#include <stdint.h>
#include <cmath>
#include <cassert>
+#include "types.h"
#include "move.h"
#include "board.h"
#include "time.h"
#include "depthstats.h"
#include "thread.h"
-typedef unsigned int uint;
class Player {
public:
@@ -340,6 +339,61 @@ class Player {
Move rollout_pattern(const Board & board, const Move & move);
};
+ class Sync {
+ RWLock lock; // stop the thread runners from doing work
+ CondVar cond; // tell the master thread that the threads are done
+ volatile bool stop; // write lock asked
+ volatile bool writelock; //is the write lock
+
+ public:
+ Sync() : stop(false), writelock(false) { }
+
+ int wrlock(){ //aquire the write lock, set stop, blocks
+ assert(writelock == false);
+
+// fprintf(stderr, "ask write lock\n");
+
+ CAS(stop, false, true);
+ int r = lock.wrlock();
+ writelock = true;
+ CAS(stop, true, false);
+// fprintf(stderr, "got write lock\n");
+ return r;
+ }
+ int rdlock(){ //aquire the read lock, blocks
+// fprintf(stderr, "Ask for read lock\n");
+ if(stop){
+// fprintf(stderr, "Spinning on read lock\n");
+ while(stop)
+ continue;
+// fprintf(stderr, "Done spinning on read lock\n");
+ }
+ int ret = lock.rdlock();
+// fprintf(stderr, "Got a read lock\n");
+ return ret;
+ }
+ int relock(){ //succeeds if stop isn't requested
+ return (stop == false);
+ }
+ int unlock(){ //unlocks the lock
+ if(writelock){
+// fprintf(stderr, "unlock read lock\n");
+ }else{
+// fprintf(stderr, "unlock write lock\n");
+ }
+ writelock = false;
+ return lock.unlock();
+ }
+ int done(){ //signals that the timeout happened or solved
+ return cond.broadcast();
+ }
+ int wait(){ //waits for the signal
+ cond.lock(); //lock the signal that defines the end condition
+ cond.wait(); //wait a signal to end (could be from the timer)
+ cond.unlock();
+ }
+ };
+
public:
static const float min_rave = 0.1;
@@ -370,12 +424,10 @@ class Player {
Board rootboard;
Node root;
- uint64_t nodes, maxnodes;
+ uword nodes, maxnodes;
vector<PlayerThread *> threads;
- RWLock lock; // stop the thread runners from doing work
- CondVar cond; // tell the master thread that the threads are done
-
+ Sync sync;
double time_used;
@@ -386,7 +438,7 @@ class Player {
set_default_params();
if(!ponder)
- lock.wrlock();
+ sync.wrlock();
}
void set_default_params(){
int s = rootboard.get_size();
@@ -411,8 +463,12 @@ class Player {
lastgoodreply = false;
instantwin = 0;
}
- ~Player(){ lock.wrlock(); root.dealloc(); }
- void timedout() { cond.broadcast(); }
+ ~Player(){
+ if(ponder)
+ sync.wrlock();
+ root.dealloc();
+ }
+ void timedout() { sync.done(); }
void reset_threads(){ //better have the write lock before calling this
for(int i = threads.size(); i < numthreads; i++)
@@ -421,15 +477,15 @@ class Player {
void set_ponder(bool p){
if(ponder != p){
- if(p) lock.unlock();
- else lock.wrlock();
+ if(p) sync.unlock();
+ else sync.wrlock();
ponder = p;
}
}
void set_board(const Board & board){
if(ponder)
- lock.wrlock();
+ sync.wrlock();
rootboard = board;
nodes -= root.dealloc();
@@ -441,15 +497,15 @@ class Player {
reset_threads();
if(ponder)
- lock.unlock();
+ sync.unlock();
}
void move(const Move & m){
if(ponder)
- lock.wrlock();
+ sync.wrlock();
rootboard.move(m, true);
- uint64_t nodesbefore = nodes;
+ uword nodesbefore = nodes;
if(keeptree){
Node child;
@@ -467,7 +523,7 @@ class Player {
root.swap_tree(child);
if(nodesbefore > 0)
- fprintf(stderr, "Nodes before: %llu, after: %llu, saved %.1f%% of the tree\n", nodesbefore, nodes, 100.0*nodes/nodesbefore);
+ fprintf(stderr, "Nodes before: %u, after: %u, saved %.1f%% of the tree\n", nodesbefore, nodes, 100.0*nodes/nodesbefore);
}else{
nodes -= root.dealloc();
root = Node();
@@ -476,7 +532,7 @@ class Player {
assert(nodes == root.size());
if(ponder)
- lock.unlock();
+ sync.unlock();
}
double gamelen(){
View
@@ -9,21 +9,23 @@
void Player::PlayerUCT::run(){
RaveMoveList movelist;
- while(1){
- player->lock.rdlock(); //wait for the write lock to come off
+// fprintf(stderr, "Runner start\n");
+ while(player->root.outcome == -1){
+ player->sync.rdlock(); //wait for the write lock to come off
+
do{
if(player->root.outcome != -1){ //solved, return early
- player->lock.unlock();
- player->cond.broadcast(); //let the main thread know
+ player->sync.done(); //let the main thread know
break;
}
runs++;
Board copy = player->rootboard;
movelist.clear();
walk_tree(copy, & player->root, movelist, 0);
- player->lock.unlock();
- }while(player->lock.tryrdlock() == 0); //fails when the write lock comes back
+ }while(player->sync.relock()); //fails when the write lock comes back
+ player->sync.unlock();
}
+// fprintf(stderr, "Runner exit\n");
}
//return the winner of the simulation
@@ -143,7 +145,7 @@ int Player::PlayerUCT::create_children(Board & board, Node * node, int toplay){
}
}
- player->nodes += temp.num();
+ PLUS(player->nodes, temp.num());
node->children.atomic_set(temp);
temp.neuter();

0 comments on commit 3b07ddf

Please sign in to comment.