From f90e798502be3e6155d092e3083fb11b76769a06 Mon Sep 17 00:00:00 2001 From: Michael Uleysky Date: Sat, 12 Sep 2015 19:15:57 +1000 Subject: [PATCH] Multithreading support --- src/Makefile | 4 +- src/deptree.cpp | 223 +++++++++++++++++++++++++++++++++--------------- src/deptree.h | 26 ++++-- src/main.cpp | 2 +- 4 files changed, 177 insertions(+), 78 deletions(-) diff --git a/src/Makefile b/src/Makefile index 71f166c..d2a23ad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ -CFLAGS=-O2 -g -std=gnu++11 -fvisibility=hidden -fpic -Wall -LDFLAGS=-fvisibility=hidden -Wl,--export-dynamic -fpic -Wall +CFLAGS=-O2 -g -std=gnu++11 -fvisibility=hidden -fpic -pthread -Wall +LDFLAGS=-fvisibility=hidden -Wl,--export-dynamic -fpic -pthread -Wall CC=g++ diff --git a/src/deptree.cpp b/src/deptree.cpp index f37b825..b9dc9c1 100644 --- a/src/deptree.cpp +++ b/src/deptree.cpp @@ -169,132 +169,190 @@ DepTree::LeafVector DepTree::FindLeafNodes() const // Multi-threaded version -void TreeEvaluate(std::mutex* mtx, int* errflag, DepTree::LeafVector* leafs, const DepTree* root) +void* TreeEvaluateM(void* arg) { - // mtx[0] - mutex for manipulating with LeafVector - // mtx[1] - mutex for manipulating with tree + struct timespec skip={0,10000000}; + DepTree::thread_params* p=reinterpret_cast(arg); DepTree* leaf; ObjectBase *ob,*eob; ObjectList* ol; bool err; + while(true) { - // Begin locked section (errflag check, leafs manipulations) - mtx[0].lock(); - // Is was error? - if(0!=errflag) {mtx[0].unlock(); return;} - // Is work finished? - if(0==root->childrens.size()) {mtx[0].unlock(); return;} - // Is jobs awaiting? - if(0==leafs->size()) {mtx[0].unlock(); std::this_thread::yield(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); continue;} + // Begin critical section (access to root) + pthread_mutex_lock(&p->root_mtx); + // Check, if all done, or error happens? + if(0==p->root->childrens.size() || 0!=p->exitcode) {pthread_mutex_unlock(&p->root_mtx); return 0;} + // End critical section + pthread_mutex_unlock(&p->root_mtx); + + // Begin critical section (access to leafs) + pthread_mutex_lock(&p->leaf_mtx); + // Check, if some work available? + if(0==p->leafs.size()) {pthread_mutex_unlock(&p->leaf_mtx); nanosleep(&skip,0); continue;} // Select working node - leaf=*(leafs->begin()); + leaf=*(p->leafs.begin()); // and remove its from list - leafs->erase(leafs->begin()); - mtx[0].unlock(); - // End locked section + p->leafs.erase(p->leafs.begin()); + // End critical section + pthread_mutex_unlock(&p->leaf_mtx); if(DepTree::SAVE==leaf->type) { err=false; + + // Begin critical section (access to G_toprint or G_tosave) + pthread_mutex_lock(&p->prsv_mtx); ol=G_tosave[leaf->index]; + // End critical section + pthread_mutex_unlock(&p->prsv_mtx); + ol->Evaluate(&err); // For list Evaluate always return 0; if(err) { COUT(ERROR)<<" in instruction save"<Dump()<<")"<exitcode=1; + return 0; } if(!Save(ol)) { - mtx[0].lock(); - *errflag=1; - mtx[0].unlock(); - return; + p->exitcode=1; + return 0; } + // This leaf can have only one parent - root + // Begin critical section (access to root) + pthread_mutex_lock(&p->root_mtx); + (*leaf->parents.begin())->childrens.erase(leaf); + // End critical section + pthread_mutex_unlock(&p->root_mtx); } if(DepTree::PRINT==leaf->type) { err=false; + + // Begin critical section (access to G_toprint or G_tosave) + pthread_mutex_lock(&p->prsv_mtx); ol=G_toprint[leaf->index]; + // End critical section + pthread_mutex_unlock(&p->prsv_mtx); + ol->Evaluate(&err); // For list Evaluate always return 0; if(err) { COUT(ERROR)<<" in instruction print"<Dump()<<")"<exitcode=1; + return 0; } if(!Print(ol)) { - mtx[0].lock(); - *errflag=1; - mtx[0].unlock(); - return; + p->exitcode=1; + return 0; } + + // Begin critical section (access to root) + pthread_mutex_lock(&p->root_mtx); + // This leaf can have only one parent - root + (*leaf->parents.begin())->childrens.erase(leaf); + // End critical section + pthread_mutex_unlock(&p->root_mtx); + } if(DepTree::VAR==leaf->type) { - err=false; + // Begin critical section (access to G_vars) + pthread_mutex_lock(&p->vars_mtx); ob=G_vars.at(leaf->name); + G_vars.erase(leaf->name); + // End critical section + pthread_mutex_unlock(&p->vars_mtx); + // Main working call + err=false; eob=ob->Evaluate(&err); if(err) { COUT(ERROR)<<" in definition of variable "<name<exitcode=1; + return 0; } // eob is evaluated object if(0!=eob) delete ob; else eob=ob; - G_vars.erase(leaf->name); // Concurrent access is safe - // Begin locked section - mtx[1].lock(); + + // Begin critical section (access to tree structure) + pthread_mutex_lock(&p->tree_mtx); for(auto& i:leaf->parents) { // leaf not children of anyone i->childrens.erase(leaf); // Replace variable on eob - if(DepTree::SAVE==i->type) G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList - if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob); + if(DepTree::SAVE==i->type) + { + // Begin critical section (access to G_toprint or G_tosave) + pthread_mutex_lock(&p->prsv_mtx); + G_tosave[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList + // End critical section + pthread_mutex_unlock(&p->prsv_mtx); + } + if(DepTree::PRINT==i->type) + { + // Begin critical section (access to G_toprint or G_tosave) + pthread_mutex_lock(&p->prsv_mtx); + G_toprint[i->index]->ReplaceVar(leaf->name,eob); // ReplaceVar always return 0 for ObjectList + // End critical section + pthread_mutex_unlock(&p->prsv_mtx); + } if(DepTree::VAR==i->type) { + // Begin critical section (access to G_vars) + pthread_mutex_lock(&p->vars_mtx); ob=G_vars[i->name]->ReplaceVar(leaf->name,eob); - if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;} + if(0!=ob) + { + delete G_vars[i->name]; + G_vars[i->name]=ob; + } + // End critical section + pthread_mutex_unlock(&p->vars_mtx); } + + // Begin critical section (access to leafs) + pthread_mutex_lock(&p->leaf_mtx); // If node have no children, it's a new leaf node - if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i); + if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i); + pthread_mutex_unlock(&p->leaf_mtx); + // End critical section } - mtx[1].unlock(); - // End locked section + // End critical section + pthread_mutex_unlock(&p->tree_mtx); delete eob; - leaf->parents.clear(); - delete leaf; } + + leaf->parents.clear(); + delete leaf; } + return 0; } // Single-threaded version -void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) +void* TreeEvaluate(void* arg) { + DepTree::thread_params* p=reinterpret_cast(arg); DepTree* leaf; ObjectBase *ob,*eob; ObjectList* ol; bool err; - while(0!=leafs->size()) + while(0!=p->leafs.size()) { // Select working node - leaf=*(leafs->begin()); + leaf=*(p->leafs.begin()); // and remove its from list - leafs->erase(leafs->begin()); + p->leafs.erase(p->leafs.begin()); if(DepTree::SAVE==leaf->type) { @@ -304,15 +362,17 @@ void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) if(err) { COUT(ERROR)<<" in instruction save"<Dump()<<")"<exitcode=1; + return 0; } // eob is evaluated object if(!Save(ol)) { - *errflag=1; - return; + p->exitcode=1; + return 0; } + // This leaf can have only one parent - root + (*leaf->parents.begin())->childrens.erase(leaf); } if(DepTree::PRINT==leaf->type) @@ -323,33 +383,36 @@ void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) if(err) { COUT(ERROR)<<" in instruction print"<Dump()<<")"<exitcode=1; + return 0; } if(!Print(ol)) { - *errflag=1; - return; + p->exitcode=1; + return 0; } + // This leaf can have only one parent - root + (*leaf->parents.begin())->childrens.erase(leaf); } if(DepTree::VAR==leaf->type) { err=false; ob=G_vars.at(leaf->name); + G_vars.erase(leaf->name); // Main working call eob=ob->Evaluate(&err); if(err) { COUT(ERROR)<<" in definition of variable "<name<exitcode=1; + return 0; } // eob is evaluated object if(0!=eob) delete ob; else eob=ob; - G_vars.erase(leaf->name); + //G_vars.erase(leaf->name); for(auto& i:leaf->parents) { // leaf not children of anyone @@ -363,21 +426,45 @@ void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) if(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;} } // If node have no children, it's a new leaf node - if(0==i->childrens.size() && DepTree::ROOT!=i->type) leafs->push_back(i); + if(0==i->childrens.size() && DepTree::ROOT!=i->type) p->leafs.push_back(i); } delete eob; - leaf->parents.clear(); - delete leaf; } + leaf->parents.clear(); + delete leaf; } + return 0; } -int DepTree::EvaluateTree() +int DepTree::EvaluateTree(unsigned int nthreads) { - int errflag=0; - LeafVector leafs=FindLeafNodes(); + DepTree::thread_params p; - TreeEvaluate(&errflag,&leafs); - return errflag; + p.exitcode=0; + p.leafs=FindLeafNodes(); + + if(1==nthreads) TreeEvaluate(&p); + else + { + pthread_t* threads=new pthread_t[nthreads-1]; + p.root=this; + pthread_mutex_init(&p.leaf_mtx,0); + pthread_mutex_init(&p.root_mtx,0); + pthread_mutex_init(&p.vars_mtx,0); + pthread_mutex_init(&p.prsv_mtx,0); + pthread_mutex_init(&p.tree_mtx,0); + while(0!=p.root->parents.size()) p.root=*(p.root->parents.begin()); + + for(unsigned int i=0;i #include #include -#include -#include +#include +#include #include "globals.h" class DepTree { typedef std::vector LeafVector; typedef std::map DepTreeVars; - enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR}; - typedef std::set NodeVector; typedef std::set CallStack; + enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR}; + + typedef struct + { + const DepTree* root; + int exitcode; + LeafVector leafs; + pthread_mutex_t leaf_mtx; + pthread_mutex_t root_mtx; + pthread_mutex_t vars_mtx; + pthread_mutex_t prsv_mtx; + pthread_mutex_t tree_mtx; + } thread_params; + NodeVector parents; NodeVector childrens; NodeType type; @@ -39,9 +51,9 @@ public: } int CreateGlobalTree(UsedType& used); - int EvaluateTree(); - friend void TreeEvaluate(std::mutex* mtx, int* errflag, LeafVector* leafs, const DepTree* root); - friend void TreeEvaluate(int* errflag, LeafVector* leafs); + int EvaluateTree(unsigned int nthreads); + friend void* TreeEvaluateM(void* arg); + friend void* TreeEvaluate (void* arg); }; #endif diff --git a/src/main.cpp b/src/main.cpp index 77124ec..0987e95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,7 +68,7 @@ int main(int argc, char** argv) else { COUT(INFO)<<"Evaluate tree "; - ret=DPTree->EvaluateTree(); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;} + ret=DPTree->EvaluateTree(options.threads); if(ret!=0) { ClearGlobals(); delete DPTree; return 1;} COUT(INFO)<<"Ok"<