Browse Source

Multithreading support

test
Michael Uleysky 9 years ago
parent
commit
f90e798502
  1. 4
      src/Makefile
  2. 219
      src/deptree.cpp
  3. 26
      src/deptree.h
  4. 2
      src/main.cpp

4
src/Makefile

@ -1,5 +1,5 @@
CFLAGS=-O2 -g -std=gnu++11 -fvisibility=hidden -fpic -Wall CFLAGS=-O2 -g -std=gnu++11 -fvisibility=hidden -fpic -pthread -Wall
LDFLAGS=-fvisibility=hidden -Wl,--export-dynamic -fpic -Wall LDFLAGS=-fvisibility=hidden -Wl,--export-dynamic -fpic -pthread -Wall
CC=g++ CC=g++

219
src/deptree.cpp

@ -169,132 +169,190 @@ DepTree::LeafVector DepTree::FindLeafNodes() const
// Multi-threaded version // 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 struct timespec skip={0,10000000};
// mtx[1] - mutex for manipulating with tree DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf; DepTree* leaf;
ObjectBase *ob,*eob; ObjectBase *ob,*eob;
ObjectList* ol; ObjectList* ol;
bool err; bool err;
while(true) while(true)
{ {
// Begin locked section (errflag check, leafs manipulations) // Begin critical section (access to root)
mtx[0].lock(); pthread_mutex_lock(&p->root_mtx);
// Is was error? // Check, if all done, or error happens?
if(0!=errflag) {mtx[0].unlock(); return;} if(0==p->root->childrens.size() || 0!=p->exitcode) {pthread_mutex_unlock(&p->root_mtx); return 0;}
// Is work finished? // End critical section
if(0==root->childrens.size()) {mtx[0].unlock(); return;} pthread_mutex_unlock(&p->root_mtx);
// 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 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 // Select working node
leaf=*(leafs->begin()); leaf=*(p->leafs.begin());
// and remove its from list // and remove its from list
leafs->erase(leafs->begin()); p->leafs.erase(p->leafs.begin());
mtx[0].unlock(); // End critical section
// End locked section pthread_mutex_unlock(&p->leaf_mtx);
if(DepTree::SAVE==leaf->type) if(DepTree::SAVE==leaf->type)
{ {
err=false; err=false;
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
ol=G_tosave[leaf->index]; ol=G_tosave[leaf->index];
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
ol->Evaluate(&err); // For list Evaluate always return 0; ol->Evaluate(&err); // For list Evaluate always return 0;
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl; COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
*errflag=1; p->exitcode=1;
return; return 0;
} }
if(!Save(ol)) if(!Save(ol))
{ {
mtx[0].lock(); p->exitcode=1;
*errflag=1; return 0;
mtx[0].unlock();
return;
} }
// 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) if(DepTree::PRINT==leaf->type)
{ {
err=false; err=false;
// Begin critical section (access to G_toprint or G_tosave)
pthread_mutex_lock(&p->prsv_mtx);
ol=G_toprint[leaf->index]; ol=G_toprint[leaf->index];
// End critical section
pthread_mutex_unlock(&p->prsv_mtx);
ol->Evaluate(&err); // For list Evaluate always return 0; ol->Evaluate(&err); // For list Evaluate always return 0;
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl; COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
*errflag=1; p->exitcode=1;
return; return 0;
} }
if(!Print(ol)) if(!Print(ol))
{ {
mtx[0].lock(); p->exitcode=1;
*errflag=1; return 0;
mtx[0].unlock();
return;
} }
// 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) 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); ob=G_vars.at(leaf->name);
G_vars.erase(leaf->name);
// End critical section
pthread_mutex_unlock(&p->vars_mtx);
// Main working call // Main working call
err=false;
eob=ob->Evaluate(&err); eob=ob->Evaluate(&err);
if(err) if(err)
{ {
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
// Begin locked section (errflag set) p->exitcode=1;
mtx[0].lock(); return 0;
*errflag=1;
mtx[0].unlock();
// End locked section
return;
} }
// eob is evaluated object // eob is evaluated object
if(0!=eob) delete ob; if(0!=eob) delete ob;
else eob=ob; else eob=ob;
G_vars.erase(leaf->name); // Concurrent access is safe
// Begin locked section // Begin critical section (access to tree structure)
mtx[1].lock(); pthread_mutex_lock(&p->tree_mtx);
for(auto& i:leaf->parents) for(auto& i:leaf->parents)
{ {
// leaf not children of anyone // leaf not children of anyone
i->childrens.erase(leaf); i->childrens.erase(leaf);
// Replace variable on eob // 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::SAVE==i->type)
if(DepTree::PRINT==i->type) G_toprint[i->index]->ReplaceVar(leaf->name,eob); {
// 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) 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); 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 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 critical section
// End locked section pthread_mutex_unlock(&p->tree_mtx);
delete eob; delete eob;
}
leaf->parents.clear(); leaf->parents.clear();
delete leaf; delete leaf;
} }
} return 0;
} }
// Single-threaded version // Single-threaded version
void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs) void* TreeEvaluate(void* arg)
{ {
DepTree::thread_params* p=reinterpret_cast<DepTree::thread_params*>(arg);
DepTree* leaf; DepTree* leaf;
ObjectBase *ob,*eob; ObjectBase *ob,*eob;
ObjectList* ol; ObjectList* ol;
bool err; bool err;
while(0!=leafs->size()) while(0!=p->leafs.size())
{ {
// Select working node // Select working node
leaf=*(leafs->begin()); leaf=*(p->leafs.begin());
// and remove its from list // and remove its from list
leafs->erase(leafs->begin()); p->leafs.erase(p->leafs.begin());
if(DepTree::SAVE==leaf->type) if(DepTree::SAVE==leaf->type)
{ {
@ -304,15 +362,17 @@ void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs)
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl; COUT(ERROR)<<" in instruction save"<<ol->Dump()<<")"<<std::endl;
*errflag=1; p->exitcode=1;
return; return 0;
} }
// eob is evaluated object // eob is evaluated object
if(!Save(ol)) if(!Save(ol))
{ {
*errflag=1; p->exitcode=1;
return; return 0;
} }
// This leaf can have only one parent - root
(*leaf->parents.begin())->childrens.erase(leaf);
} }
if(DepTree::PRINT==leaf->type) if(DepTree::PRINT==leaf->type)
@ -323,33 +383,36 @@ void TreeEvaluate(int* errflag, DepTree::LeafVector* leafs)
if(err) if(err)
{ {
COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl; COUT(ERROR)<<" in instruction print"<<ol->Dump()<<")"<<std::endl;
*errflag=1; p->exitcode=1;
return; return 0;
} }
if(!Print(ol)) if(!Print(ol))
{ {
*errflag=1; p->exitcode=1;
return; return 0;
} }
// This leaf can have only one parent - root
(*leaf->parents.begin())->childrens.erase(leaf);
} }
if(DepTree::VAR==leaf->type) if(DepTree::VAR==leaf->type)
{ {
err=false; err=false;
ob=G_vars.at(leaf->name); ob=G_vars.at(leaf->name);
G_vars.erase(leaf->name);
// Main working call // Main working call
eob=ob->Evaluate(&err); eob=ob->Evaluate(&err);
if(err) if(err)
{ {
COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl; COUT(ERROR)<<" in definition of variable "<<leaf->name<<std::endl;
*errflag=1; p->exitcode=1;
return; return 0;
} }
// eob is evaluated object // eob is evaluated object
if(0!=eob) delete ob; if(0!=eob) delete ob;
else eob=ob; else eob=ob;
G_vars.erase(leaf->name); //G_vars.erase(leaf->name);
for(auto& i:leaf->parents) for(auto& i:leaf->parents)
{ {
// leaf not children of anyone // 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(0!=ob) {delete G_vars[i->name]; G_vars[i->name]=ob;}
} }
// If node have no children, it's a new leaf node // 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; delete eob;
}
leaf->parents.clear(); leaf->parents.clear();
delete leaf; delete leaf;
} }
} return 0;
} }
int DepTree::EvaluateTree() int DepTree::EvaluateTree(unsigned int nthreads)
{ {
int errflag=0; DepTree::thread_params p;
LeafVector leafs=FindLeafNodes();
p.exitcode=0;
p.leafs=FindLeafNodes();
TreeEvaluate(&errflag,&leafs); if(1==nthreads) TreeEvaluate(&p);
return errflag; 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<nthreads-1;++i) pthread_create(threads+i,0,&TreeEvaluateM,&p);
TreeEvaluateM(&p);
for(unsigned int i=0;i<nthreads-1;++i) pthread_join(threads[i],0);
delete[] threads;
pthread_mutex_destroy(&p.leaf_mtx);
pthread_mutex_destroy(&p.root_mtx);
pthread_mutex_destroy(&p.vars_mtx);
pthread_mutex_destroy(&p.prsv_mtx);
pthread_mutex_destroy(&p.tree_mtx);
}
return p.exitcode;
} }

26
src/deptree.h

@ -3,18 +3,30 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include <string> #include <string>
#include <mutex> #include <pthread.h>
#include <thread> #include <time.h>
#include "globals.h" #include "globals.h"
class DepTree class DepTree
{ {
typedef std::vector<DepTree*> LeafVector; typedef std::vector<DepTree*> LeafVector;
typedef std::map<std::string,DepTree*> DepTreeVars; typedef std::map<std::string,DepTree*> DepTreeVars;
enum NodeType {NOTDEF,ROOT,SAVE,PRINT,VAR};
typedef std::set<DepTree*> NodeVector; typedef std::set<DepTree*> NodeVector;
typedef std::set<DepTree*> CallStack; typedef std::set<DepTree*> 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 parents;
NodeVector childrens; NodeVector childrens;
NodeType type; NodeType type;
@ -39,9 +51,9 @@ public:
} }
int CreateGlobalTree(UsedType& used); int CreateGlobalTree(UsedType& used);
int EvaluateTree(); int EvaluateTree(unsigned int nthreads);
friend void TreeEvaluate(std::mutex* mtx, int* errflag, LeafVector* leafs, const DepTree* root); friend void* TreeEvaluateM(void* arg);
friend void TreeEvaluate(int* errflag, LeafVector* leafs); friend void* TreeEvaluate (void* arg);
}; };
#endif #endif

2
src/main.cpp

@ -68,7 +68,7 @@ int main(int argc, char** argv)
else else
{ {
COUT(INFO)<<"Evaluate tree "; 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"<<std::endl; COUT(INFO)<<"Ok"<<std::endl;
} }

Loading…
Cancel
Save