/* $Id: CbcThread.hpp 1902 2013-04-10 16:58:16Z stefan $ */ // Copyright (C) 2009, International Business Machines // Corporation and others. All Rights Reserved. // This code is licensed under the terms of the Eclipse Public License (EPL). #ifndef CbcThread_H #define CbcThread_H #include "CbcModel.hpp" #include "CbcNode.hpp" class OsiObject; class OsiCuts; #ifdef CBC_THREAD class CbcThread; // Use pthreads #define CBC_PTHREAD #ifdef CBC_PTHREAD #include typedef struct { pthread_t thr; long status; } Coin_pthread_t; #endif //#define THREAD_DEBUG 1 /** A class to encapsulate specific thread stuff To use another api with same style - you just need to implement these methods. At present just pthreads */ class CbcSpecificThread { public: // Default Constructor CbcSpecificThread (); // Useful Constructor CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex); virtual ~CbcSpecificThread(); // Useful stuff void setUsefulStuff (CbcSpecificThread * master, void *& masterMutex); /** Locks a thread if parallel so that stuff like cut pool can be updated and/or used. */ void lockThread(); /** Unlocks a thread if parallel to say cut pool stuff not needed */ void unlockThread(); /// Locks a thread for testing whether to start etc void lockThread2(bool doAnyway = false); /// Unlocks a thread for testing whether to start etc void unlockThread2(bool doAnyway = false); /// Signal void signal(); /// Timed wait in nanoseconds - if negative then seconds void timedWait(int time); /// Actually starts a thread void startThread(void * (*routine ) (void *), CbcThread * thread); /// Exits thread (called from master) - return code should be zero int exit(); /// Exits thread void exitThread(); /// Get status int status() const; /// Set status void setStatus(int value); //} public: // private: CbcSpecificThread * basePointer_; // for getting main mutex and threadid of base #ifdef CBC_PTHREAD pthread_mutex_t *masterMutex_; // for synchronizing pthread_mutex_t mutex2_; // for waking up threads pthread_cond_t condition2_; // for waking up thread Coin_pthread_t threadId_; #endif bool locked_; // For mutex2 }; /** A class to encapsulate thread stuff */ class CbcThread { private: void gutsOfDelete(); void gutsOfCopy(const CbcThread & rhs); public: // Default Constructor CbcThread (); virtual ~CbcThread(); /// Fills in useful stuff void setUsefulStuff (CbcModel * model, int deterministic, CbcModel * baseModel, CbcThread * master, void *& masterMutex); /** Locks a thread if parallel so that stuff like cut pool can be updated and/or used. */ void lockThread(); /** Unlocks a thread if parallel to say cut pool stuff not needed */ void unlockThread(); /// Returns true if locked inline bool isLocked() const { return locked_; } /** Wait for child to have return code NOT == to currentCode type - 0 timed wait 1 wait returns true if return code changed */ bool wait(int type, int currentCode); /// Just wait for so many nanoseconds void waitNano(int time); /// Signal child to carry on void signal(); /// Lock from master with mutex2 and signal before lock void lockFromMaster(); /// Unlock from master with mutex2 and signal after unlock void unlockFromMaster(); /// Lock from thread with mutex2 and signal before lock void lockFromThread(); /// Unlock from thread with mutex2 and signal after unlock void unlockFromThread(); /// Exits thread (called from master) - return code should be zero int exit(); /// Exits thread void exitThread(); /// Waits until returnCode_ goes to zero void waitThread(); /// Get status inline int status() const { return threadStuff_.status(); } /// Set status inline void setStatus(int value) { threadStuff_.setStatus( value); } /// Get return code inline int returnCode() const { return returnCode_; } /// Set return code inline void setReturnCode(int value) { returnCode_ = value; } /// Get base model inline CbcModel * baseModel() const { return baseModel_; } /// Get this model inline CbcModel * thisModel() const { return thisModel_; } /// Get node inline CbcNode * node() const { return node_; } /// Set node inline void setNode(CbcNode * node) { node_ = node; } /// Get created node inline CbcNode * createdNode() const { return createdNode_; } /// Set created node inline void setCreatedNode(CbcNode * node) { createdNode_ = node; } /// Get dantzig state inline int dantzigState() const { return dantzigState_; } /// Set dantzig state inline void setDantzigState(int value) { dantzigState_ = value; } /// Get time in thread inline double timeInThread() const { return timeInThread_; } /// Increment time in thread inline void incrementTimeInThread(double value) { timeInThread_ += value; } /// Get time waiting to start inline double timeWaitingToStart() const { return timeWaitingToStart_; } /// Increment time waiting to start inline void incrementTimeWaitingToStart(double value) { timeWaitingToStart_ += value; } /// Get time locked inline double timeLocked() const { return timeLocked_; } /// Increment time locked inline void incrementTimeLocked(double value) { timeLocked_ += value; } /// Get time waiting to lock inline double timeWaitingToLock() const { return timeWaitingToLock_; } /// Increment time waiting to lock inline void incrementTimeWaitingToLock(double value) { timeWaitingToLock_ += value; } /// Get if deterministic inline int deterministic() const { return deterministic_; } /// Get maxDeleteNode inline int maxDeleteNode() const { return maxDeleteNode_; } /// Set maxDeleteNode inline void setMaxDeleteNode(int value) { maxDeleteNode_ = value; } /// Get nDeleteNode (may be fake i.e. defaultParallelIterations_) inline int nDeleteNode() const { return nDeleteNode_; } /// Set nDeleteNode (may be fake i.e. defaultParallelIterations_) inline void setNDeleteNode(int value) { nDeleteNode_ = value; } /// Clear delNode inline void clearDelNode() { delete delNode_; delNode_ = NULL; } /// Set fake delNode to pass across OsiCuts inline void fakeDelNode(CbcNode ** delNode) { delNode_ = delNode; } /// Get delNode inline CbcNode ** delNode() const { return delNode_; } /// Set delNode inline void setDelNode(CbcNode ** delNode) { delNode_ = delNode; } /// Get number times locked inline int numberTimesLocked() const { return numberTimesLocked_; } /// Get number times unlocked inline int numberTimesUnlocked() const { return numberTimesUnlocked_; } /// Get number of nodes this time inline int nodesThisTime() const { return nodesThisTime_; } /// Set number of nodes this time inline void setNodesThisTime(int value) { nodesThisTime_ = value; } /// Get number of iterations this time inline int iterationsThisTime() const { return iterationsThisTime_; } /// Set number of iterations this time inline void setIterationsThisTime(int value) { iterationsThisTime_ = value; } /// Get save stuff array inline int * saveStuff() { return saveStuff_; } /// Say if locked inline bool locked() const { return locked_; } public: // private: CbcSpecificThread threadStuff_; CbcModel * baseModel_; CbcModel * thisModel_; CbcNode * node_; // filled in every time CbcNode * createdNode_; // filled in every time on return CbcThread * master_; // points back to master thread int returnCode_; // -1 available, 0 busy, 1 finished , 2?? double timeLocked_; double timeWaitingToLock_; double timeWaitingToStart_; double timeInThread_; double timeWhenLocked_; // time when thread got lock (in seconds) int numberTimesLocked_; int numberTimesUnlocked_; int numberTimesWaitingToStart_; int saveStuff_[2]; int dantzigState_; // 0 unset, -1 waiting to be set, 1 set bool locked_; int nDeleteNode_; CbcNode ** delNode_; int maxDeleteNode_; int nodesThisTime_; int iterationsThisTime_; int deterministic_; #ifdef THREAD_DEBUG public: int threadNumber_; int lockCount_; #endif }; /** Base model */ class CbcBaseModel { public: // Default Constructor CbcBaseModel (); /** Constructor with model type -1 cuts 0 opportunistic 1 deterministic */ /** Constructor with model type -1 cuts 0 opportunistic 1 deterministic */ CbcBaseModel (CbcModel & model, int type); virtual ~CbcBaseModel(); /** Stop all threads -1 just check all in good state 0 actually stop */ void stopThreads(int type); /** Wait for threads in tree type 0 - tree looks empty - see if any nodes outstanding 1 - tree not empty 2 - finish and do statistics returns non-zero if keep going */ int waitForThreadsInTree(int type); /** Wait for threads n parallel cuts type 0 - parallel cuts 1 - finishing parallel cuts */ void waitForThreadsInCuts(int type, OsiCuts * eachCuts, int whichGenerator); /// Split model and do work in deterministic parallel void deterministicParallel(); /** Locks a thread if parallel so that stuff like cut pool can be updated and/or used. */ inline void lockThread() { children_[numberThreads_].lockThread(); } /** Unlocks a thread if parallel to say cut pool stuff not needed */ inline void unlockThread() { children_[numberThreads_].unlockThread(); } /// Returns true if locked inline bool isLocked() const { return children_[numberThreads_].locked(); } /// Returns pointer to master thread CbcThread * masterThread() const; /// Returns pointer to a thread model inline CbcModel * model(int i) const { return threadModel_[i]; } /// Sets Dantzig state in children void setDantzigState(); private: /// Number of children int numberThreads_; /// Child models (with base model at end) CbcThread * children_; /** type -1 cuts 0 opportunistic 1 deterministic */ int type_; int * threadCount_; CbcModel ** threadModel_; int numberObjects_; OsiObject ** saveObjects_; int threadStats_[6]; int defaultParallelIterations_; int defaultParallelNodes_; }; #else // Dummy threads /** A class to encapsulate thread stuff */ class CbcThread { public: // Default Constructor CbcThread () {} virtual ~CbcThread() {} }; /** Base model */ class CbcBaseModel { public: // Default Constructor (not declared here so that CbcThread.cpp not empty) CbcBaseModel (); virtual ~CbcBaseModel() {} }; #endif #endif