source: trunk/Cbc/src/CbcThread.cpp @ 2081

Last change on this file since 2081 was 2081, checked in by forrest, 5 years ago

zerohalf thread safety plus restart with deterministic parallel

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 68.7 KB
Line 
1/* $Id: CbcThread.cpp 2081 2014-09-25 11:31:17Z forrest $ */
2// Copyright (C) 2002, International Business Machines
3// Corporation and others.  All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#if defined(_MSC_VER)
7// Turn off compiler warning about long names
8#  pragma warning(disable:4786)
9#endif
10
11#include "CbcConfig.h"
12
13//#define THREAD_DEBUG
14#include <string>
15#include <cassert>
16#include <cmath>
17#include <cfloat>
18
19#include "CbcEventHandler.hpp"
20
21#include "OsiSolverInterface.hpp"
22#include "OsiRowCutDebugger.hpp"
23#include "CbcThread.hpp"
24#include "CbcTree.hpp"
25#include "CbcHeuristic.hpp"
26#include "CbcCutGenerator.hpp"
27#include "CbcModel.hpp"
28#include "CbcFathom.hpp"
29#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
30#include "ClpDualRowDantzig.hpp"
31#include "OsiAuxInfo.hpp"
32
33#include "CoinTime.hpp"
34#ifdef CBC_THREAD
35/// Thread functions
36static void * doNodesThread(void * voidInfo);
37static void * doCutsThread(void * voidInfo);
38static void * doHeurThread(void * voidInfo);
39// Default Constructor
40CbcSpecificThread::CbcSpecificThread ()
41        : basePointer_(NULL),
42        masterMutex_(NULL),
43        locked_(false)
44{
45#ifdef CBC_PTHREAD
46    pthread_mutex_init(&mutex2_, NULL);
47    pthread_cond_init(&condition2_, NULL);
48    threadId_.status = 0;
49#else
50#endif
51}
52// Useful Constructor
53CbcSpecificThread::CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex)
54        : basePointer_(master),
55        masterMutex_(masterMutex),
56        locked_(false)
57
58{
59#ifdef CBC_PTHREAD
60    pthread_mutex_init(&mutex2_, NULL);
61    pthread_cond_init(&condition2_, NULL);
62    threadId_.status = 0;
63#else
64#endif
65
66}
67// Useful stuff
68void
69CbcSpecificThread::setUsefulStuff (CbcSpecificThread * master, void *& masterMutex)
70
71{
72#ifdef CBC_PTHREAD
73    basePointer_ = master;
74    if (masterMutex) {
75        masterMutex_ = reinterpret_cast<pthread_mutex_t *>(masterMutex);
76    } else {
77        // create master mutex
78        masterMutex_ = new pthread_mutex_t;
79        pthread_mutex_init(masterMutex_, NULL);
80        masterMutex = reinterpret_cast<void *>(masterMutex_);
81    }
82#else
83#endif
84}
85
86CbcSpecificThread::~CbcSpecificThread()
87{
88#ifdef CBC_PTHREAD
89    pthread_mutex_destroy (&mutex2_);
90    if (basePointer_ == this) {
91        pthread_mutex_destroy (masterMutex_);
92        delete masterMutex_;
93    }
94#else
95#endif
96}
97/*
98  Locks a thread if parallel so that stuff like cut pool
99  can be updated and/or used.
100*/
101void
102CbcSpecificThread::lockThread()
103{
104#ifdef CBC_PTHREAD
105    // Use master mutex
106    assert (basePointer_->masterMutex_ == masterMutex_);
107    pthread_mutex_lock (masterMutex_);
108#else
109#endif
110}
111/*
112  Unlocks a thread if parallel to say cut pool stuff not needed
113*/
114void
115CbcSpecificThread::unlockThread()
116{
117#ifdef CBC_PTHREAD
118    // Use master mutex
119    pthread_mutex_unlock (masterMutex_);
120#else
121#endif
122}
123//  Locks a thread for testing whether to start etc
124void
125CbcSpecificThread::lockThread2(bool doAnyway)
126{
127    if (!locked_ || doAnyway) {
128#ifdef CBC_PTHREAD
129        pthread_mutex_lock (&mutex2_);
130#else
131#endif
132        locked_ = true;
133    }
134}
135//  Unlocks a thread for testing whether to start etc
136void
137CbcSpecificThread::unlockThread2(bool doAnyway)
138{
139    if (locked_ || doAnyway) {
140#ifdef CBC_PTHREAD
141        pthread_mutex_unlock (&mutex2_);
142#else
143#endif
144        locked_ = false;
145    }
146}
147#ifdef HAVE_CLOCK_GETTIME
148inline int my_gettime(struct timespec* tp)
149{
150    return clock_gettime(CLOCK_REALTIME, tp);
151}
152#else
153#ifndef _MSC_VER
154inline int my_gettime(struct timespec* tp)
155{
156    struct timeval tv;
157    int ret = gettimeofday(&tv, NULL);
158    tp->tv_sec = tv.tv_sec;
159    tp->tv_nsec = tv.tv_usec * 1000;
160    return ret;
161}
162#else
163inline int my_gettime(struct timespec* tp)
164{
165    double t = CoinGetTimeOfDay();
166    tp->tv_sec = (int)floor(t);
167    tp->tv_nsec = (int)((tp->tv_sec - floor(t)) / 1000000.0);
168    return 0;
169}
170#endif
171#endif
172// Get time
173static double getTime()
174{
175    struct timespec absTime2;
176    my_gettime(&absTime2);
177    double time2 = absTime2.tv_sec + 1.0e-9 * 
178      static_cast<double>(absTime2.tv_nsec);
179    return time2;
180}
181// Timed wait in nanoseconds - if negative then seconds
182void
183CbcSpecificThread::timedWait(int time)
184{
185
186#ifdef CBC_PTHREAD
187    struct timespec absTime;
188    my_gettime(&absTime);
189    if (time > 0) {
190        absTime.tv_nsec += time;
191        if (absTime.tv_nsec >= 1000000000) {
192            absTime.tv_nsec -= 1000000000;
193            absTime.tv_sec++;
194        }
195    } else {
196        absTime.tv_sec -= time;
197    }
198    pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
199#else
200#endif
201}
202// Signal
203void
204CbcSpecificThread::signal()
205{
206#ifdef CBC_PTHREAD
207    pthread_cond_signal(&condition2_);
208#else
209#endif
210}
211// Actually starts a thread
212void
213CbcSpecificThread::startThread(void * (*routine ) (void *), CbcThread * thread)
214{
215#ifdef CBC_PTHREAD
216    pthread_create(&(threadId_.thr), NULL, routine, thread);
217    threadId_.status = 1;
218#else
219#endif
220}
221// Exits thread (from master)
222int
223CbcSpecificThread::exit()
224{
225#ifdef CBC_PTHREAD
226    pthread_cond_signal(&condition2_); // unlock
227    return pthread_join(threadId_.thr, NULL);
228#else
229#endif
230}
231// Exits thread
232void
233CbcSpecificThread::exitThread()
234{
235#ifdef CBC_PTHREAD
236    pthread_mutex_unlock(&mutex2_);
237    pthread_exit(NULL);
238#else
239#endif
240
241}
242// Get status
243int
244CbcSpecificThread::status() const
245{
246#ifdef CBC_PTHREAD
247    return static_cast<int>(threadId_.status);
248#else
249#endif
250}
251// Set status
252void
253CbcSpecificThread::setStatus(int value)
254{
255#ifdef CBC_PTHREAD
256    threadId_.status = value;
257#else
258#endif
259}
260// Parallel heuristics
261void
262parallelHeuristics (int numberThreads,
263                    int sizeOfData,
264                    void * argBundle)
265{
266    Coin_pthread_t * threadId = new Coin_pthread_t [numberThreads];
267    char * args = reinterpret_cast<char *>(argBundle);
268    for (int i = 0; i < numberThreads; i++) {
269        pthread_create(&(threadId[i].thr), NULL, doHeurThread,
270                       args + i*sizeOfData);
271    }
272    // now wait
273    for (int i = 0; i < numberThreads; i++) {
274        pthread_join(threadId[i].thr, NULL);
275    }
276    delete [] threadId;
277}
278// End of specific thread stuff
279
280/// Default constructor
281CbcThread::CbcThread()
282        :
283        baseModel_(NULL),
284        thisModel_(NULL),
285        node_(NULL), // filled in every time
286        createdNode_(NULL), // filled in every time on return
287        returnCode_(-1), // -1 available, 0 busy, 1 finished , 2??
288        timeLocked_(0.0),
289        timeWaitingToLock_(0.0),
290        timeWaitingToStart_(0.0),
291        timeInThread_(0.0),
292        numberTimesLocked_(0),
293        numberTimesUnlocked_(0),
294        numberTimesWaitingToStart_(0),
295        dantzigState_(0), // 0 unset, -1 waiting to be set, 1 set
296        locked_(false),
297        nDeleteNode_(0),
298        delNode_(NULL),
299        maxDeleteNode_(0),
300        nodesThisTime_(0),
301        iterationsThisTime_(0),
302        deterministic_(0)
303{
304}
305void
306CbcThread::gutsOfDelete()
307{
308    baseModel_ = NULL;
309    thisModel_ = NULL;
310    node_ = NULL;
311    createdNode_ = NULL;
312    delNode_ = NULL;
313}
314// Destructor
315CbcThread::~CbcThread()
316{
317}
318// Fills in useful stuff
319void
320CbcThread::setUsefulStuff (CbcModel * model, int deterministic, CbcModel * baseModel,
321                           CbcThread * master,
322                           void *& masterMutex)
323{
324    baseModel_ = baseModel;
325    thisModel_ = model;
326    deterministic_ = deterministic;
327    threadStuff_.setUsefulStuff(&master->threadStuff_, masterMutex);
328    node_ = NULL;
329    createdNode_ = NULL;
330    master_ = master;
331    returnCode_ = -1;
332    timeLocked_ = 0.0;
333    timeWaitingToLock_ = 0.0;
334    timeWaitingToStart_ = 0.0;
335    timeInThread_ = 0.0;
336    numberTimesLocked_ = 0;
337    numberTimesUnlocked_ = 0;
338    numberTimesWaitingToStart_ = 0;
339    dantzigState_ = 0; // 0 unset, -1 waiting to be set, 1 set
340    locked_ = false;
341    delNode_ = NULL;
342    maxDeleteNode_ = 0;
343    nDeleteNode_ = 0;
344    nodesThisTime_ = 0;
345    iterationsThisTime_ = 0;
346    if (model != baseModel) {
347        // thread
348        thisModel_->setInfoInChild(-3, this);
349        if (deterministic_ >= 0)
350            thisModel_->moveToModel(baseModel, -1);
351        if (deterministic == -1)
352            threadStuff_.startThread( doCutsThread, this);
353        else
354            threadStuff_.startThread( doNodesThread, this);
355    }
356}
357/*
358  Locks a thread if parallel so that stuff like cut pool
359  can be updated and/or used.
360*/
361void
362CbcThread::lockThread()
363{
364    if (!locked_) {
365        double time2 = getTime();
366        threadStuff_.lockThread();
367        locked_ = true;
368        timeWhenLocked_ = getTime();
369        timeWaitingToLock_ += timeWhenLocked_ - time2;;
370        numberTimesLocked_++;
371#ifdef THREAD_DEBUG
372        lockCount_ ++;
373#if THREAD_DEBUG>1
374        if (threadNumber_ == -1)
375            printf("locking master %d\n", lockCount_);
376        else
377            printf("locking thread %d %d\n", threadNumber_, lockCount_);
378#endif
379    } else {
380        if (threadNumber_ == -1)
381            printf("master already locked %d\n", lockCount_);
382        else
383            printf("thread already locked %d %d\n", threadNumber_, lockCount_);
384#endif
385    }
386}
387/*
388  Unlocks a thread if parallel
389*/
390void
391CbcThread::unlockThread()
392{
393    if (locked_) {
394        locked_ = false;
395        threadStuff_.unlockThread();
396        double time2 = getTime();
397        timeLocked_ += time2 - timeWhenLocked_;
398        numberTimesUnlocked_++;
399#ifdef THREAD_DEBUG
400#if THREAD_DEBUG>1
401        if (threadNumber_ == -1)
402            printf("unlocking master %d\n", lockCount_);
403        else
404            printf("unlocking thread %d %d\n", threadNumber_, lockCount_);
405#endif
406    } else {
407        if (threadNumber_ == -1)
408            printf("master already unlocked %d\n", lockCount_);
409        else
410            printf("thread already unlocked %d %d\n", threadNumber_, lockCount_);
411#endif
412    }
413}
414/* Wait for child to have return code NOT == to currentCode
415   type - 0 timed wait
416   1 wait
417   returns true if return code changed */
418bool
419CbcThread::wait(int type, int currentCode)
420{
421    if (!type) {
422        // just timed wait
423        master_->threadStuff_.lockThread2();
424        master_->threadStuff_.timedWait(1000000);
425        master_->threadStuff_.unlockThread2();
426    } else {
427        // wait until return code changes
428        while (returnCode_ == currentCode) {
429            threadStuff_.signal();
430            master_->threadStuff_.lockThread2();
431            master_->threadStuff_.timedWait(1000000);
432            master_->threadStuff_.unlockThread2();
433        }
434    }
435    return (returnCode_ != currentCode);
436}
437#if 0
438pthread_cond_signal(&condition2_);
439-
440if (!locked_)
441{
442    pthread_mutex_lock (&mutex2_);
443    locked_ = true;
444}
445-
446pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
447-
448if (locked_)
449{
450    pthread_mutex_unlock (&mutex2_);
451    locked_ = false;
452}
453#endif
454// Waits until returnCode_ goes to zero
455void
456CbcThread::waitThread()
457{
458    double time = getTime();
459    threadStuff_.lockThread2();
460    while (returnCode_) {
461        threadStuff_.timedWait(-10); // 10 seconds
462    }
463    timeWaitingToStart_ += getTime() - time;
464    numberTimesWaitingToStart_++;
465}
466// Just wait for so many nanoseconds
467void
468CbcThread::waitNano(int time)
469{
470    threadStuff_.lockThread2();
471    threadStuff_.timedWait(time);
472    threadStuff_.unlockThread2();
473}
474// Signal child to carry on
475void
476CbcThread::signal()
477{
478    threadStuff_.signal();
479}
480// Lock from master with mutex2 and signal before lock
481void
482CbcThread::lockFromMaster()
483{
484    threadStuff_.signal();
485    master_->threadStuff_.lockThread2(true);
486}
487// Unlock from master with mutex2 and signal after unlock
488void
489CbcThread::unlockFromMaster()
490{
491    master_->threadStuff_.unlockThread2(true); // unlock anyway
492    threadStuff_.signal();
493}
494// Lock from thread with mutex2 and signal before lock
495void
496CbcThread::lockFromThread()
497{
498    master_->threadStuff_.signal();
499    threadStuff_.lockThread2();
500}
501// Unlock from thread with mutex2 and signal after unlock
502void
503CbcThread::unlockFromThread()
504{
505    master_->threadStuff_.signal();
506    threadStuff_.unlockThread2();
507}
508// Exits thread (from master)
509int
510CbcThread::exit()
511{
512    return threadStuff_.exit();
513}
514// Exits thread
515void
516CbcThread::exitThread()
517{
518    threadStuff_.exitThread();
519}
520// Default constructor
521CbcBaseModel::CbcBaseModel()
522        :
523        numberThreads_(0),
524        children_(NULL),
525        type_(0),
526        threadCount_(NULL),
527        threadModel_(NULL),
528        numberObjects_(0),
529        saveObjects_(NULL),
530        defaultParallelIterations_(400),
531        defaultParallelNodes_(2)
532{
533}
534// Constructor with model
535CbcBaseModel::CbcBaseModel (CbcModel & model,  int type)
536        :
537        children_(NULL),
538        type_(type),
539        threadCount_(NULL),
540        threadModel_(NULL),
541        numberObjects_(0),
542        saveObjects_(NULL),
543        defaultParallelIterations_(400),
544        defaultParallelNodes_(2)
545{
546    numberThreads_ = model.getNumberThreads();
547    if (numberThreads_) {
548        children_ = new CbcThread [numberThreads_+1];
549        // Do a partial one for base model
550        void * mutex_main = NULL;
551        children_[numberThreads_].setUsefulStuff(&model, type_, &model,
552                children_ + numberThreads_, mutex_main);
553#ifdef THREAD_DEBUG
554        children_[numberThreads_].threadNumber_ = -1;
555        children_[numberThreads_].lockCount_ = 0;
556#endif
557        threadCount_ = new int [numberThreads_];
558        CoinZeroN(threadCount_, numberThreads_);
559        threadModel_ = new CbcModel * [numberThreads_+1];
560        memset(threadStats_, 0, sizeof(threadStats_));
561        if (type_ > 0) {
562            // May need for deterministic
563            numberObjects_ = model.numberObjects();
564            saveObjects_ = new OsiObject * [numberObjects_];
565            for (int i = 0; i < numberObjects_; i++) {
566                saveObjects_[i] = model.object(i)->clone();
567            }
568        }
569        // we don't want a strategy object
570        CbcStrategy * saveStrategy = model.strategy();
571        model.setStrategy(NULL);
572        for (int i = 0; i < numberThreads_; i++) {
573            //threadModel_[i] = new CbcModel(model, true);
574            threadModel_[i] = model. clone (true);
575            threadModel_[i]->synchronizeHandlers(1);
576#ifdef COIN_HAS_CLP
577            // Solver may need to know about model
578            CbcModel * thisModel = threadModel_[i];
579            CbcOsiSolver * solver =
580                dynamic_cast<CbcOsiSolver *>(thisModel->solver()) ;
581            if (solver)
582                solver->setCbcModel(thisModel);
583#endif
584            children_[i].setUsefulStuff(threadModel_[i], type_, &model,
585                                        children_ + numberThreads_, mutex_main);
586#ifdef THREAD_DEBUG
587            children_[i].threadNumber_ = i;
588            children_[i].lockCount_ = 0;
589#endif
590        }
591        model.setStrategy(saveStrategy);
592    }
593}
594// Stop threads
595void
596CbcBaseModel::stopThreads(int type)
597{
598    if (type < 0) {
599        // max nodes ?
600        bool finished = false;
601        while (!finished) {
602          finished = true;
603          for (int i = 0; i < numberThreads_; i++) {
604            if (abs(children_[i].returnCode()) != 1) {
605              children_[i].wait(1, 0); 
606              finished=false;
607            }
608          }
609        }
610        return;
611    }
612    for (int i = 0; i < numberThreads_; i++) {
613        children_[i].wait(1, 0);
614        assert (children_[i].returnCode() == -1);
615        threadModel_[i]->setInfoInChild(-2, NULL);
616        children_[i].setReturnCode( 0);
617        children_[i].exit();
618        children_[i].setStatus( 0);
619    }
620    // delete models and solvers
621    for (int i = 0; i < numberThreads_; i++) {
622        threadModel_[i]->setInfoInChild(type_, NULL);
623        delete threadModel_[i];
624    }
625    delete [] children_;
626    delete [] threadModel_;
627    for (int i = 0; i < numberObjects_; i++)
628        delete saveObjects_[i];
629    delete [] saveObjects_;
630    children_ = NULL;
631    threadModel_ = NULL;
632    saveObjects_ = NULL;
633    numberObjects_ = 0;
634    numberThreads_ = 0;
635}
636// Wait for threads in tree
637int
638CbcBaseModel::waitForThreadsInTree(int type)
639{
640    CbcModel * baseModel = children_[0].baseModel();
641    int anyLeft = 0;
642    // May be able to combine parts later
643
644    if (type == 0) {
645        bool locked = true;
646#ifdef COIN_DEVELOP
647        printf("empty\n");
648#endif
649        // may still be outstanding nodes
650        while (true) {
651            int iThread;
652            for (iThread = 0; iThread < numberThreads_; iThread++) {
653                if (children_[iThread].status()) {
654                    if (children_[iThread].returnCode() == 0)
655                        break;
656                }
657            }
658            if (iThread < numberThreads_) {
659#ifdef COIN_DEVELOP
660                printf("waiting for thread %d code 0\n", iThread);
661#endif
662                unlockThread();
663                locked = false;
664                children_[iThread].wait(1, 0);
665                assert(children_[iThread].returnCode() == 1);
666                threadModel_[iThread]->moveToModel(baseModel, 1);
667#ifdef THREAD_PRINT
668                printf("off thread2 %d node %x\n", iThread, children_[iThread].node());
669#endif
670                children_[iThread].setNode(NULL);
671                anyLeft = 1;
672                assert (children_[iThread].returnCode() == 1);
673                if (children_[iThread].dantzigState() == -1) {
674                    // 0 unset, -1 waiting to be set, 1 set
675                    children_[iThread].setDantzigState(1);
676                    CbcModel * model = children_[iThread].thisModel();
677                    OsiClpSolverInterface * clpSolver2
678                    = dynamic_cast<OsiClpSolverInterface *> (model->solver());
679                    assert (clpSolver2);
680                    ClpSimplex * simplex2 = clpSolver2->getModelPtr();
681                    ClpDualRowDantzig dantzig;
682                    simplex2->setDualRowPivotAlgorithm(dantzig);
683                }
684                // say available
685                children_[iThread].setReturnCode( -1);
686                threadStats_[4]++;
687#ifdef COIN_DEVELOP
688                printf("thread %d code now -1\n", iThread);
689#endif
690                break;
691            } else {
692#ifdef COIN_DEVELOP
693                printf("no threads at code 0 \n");
694#endif
695                // now check if any have just finished
696                for (iThread = 0; iThread < numberThreads_; iThread++) {
697                    if (children_[iThread].status()) {
698                        if (children_[iThread].returnCode() == 1)
699                            break;
700                    }
701                }
702                if (iThread < numberThreads_) {
703                    unlockThread();
704                    locked = false;
705                    threadModel_[iThread]->moveToModel(baseModel, 1);
706#ifdef THREAD_PRINT
707                    printf("off thread3 %d node %x\n", iThread, children_[iThread].node());
708#endif
709                    children_[iThread].setNode(NULL);
710                    anyLeft = 1;
711                    assert (children_[iThread].returnCode() == 1);
712                    // say available
713                    children_[iThread].setReturnCode( -1);
714                    threadStats_[4]++;
715#ifdef COIN_DEVELOP
716                    printf("thread %d code now -1\n", iThread);
717#endif
718                    break;
719                }
720            }
721            if (!baseModel->tree()->empty()) {
722#ifdef COIN_DEVELOP
723                printf("tree not empty!!!!!!\n");
724#endif
725                if (locked)
726                    unlockThread();
727                return 1;
728                break;
729            }
730            for (iThread = 0; iThread < numberThreads_; iThread++) {
731                if (children_[iThread].status()) {
732                    if (children_[iThread].returnCode() != -1) {
733                        printf("bad end of tree\n");
734                        abort();
735                    }
736                }
737            }
738            break;
739        }
740#ifdef COIN_DEVELOP
741        printf("finished ************\n");
742#endif
743        if (locked)
744            unlockThread();
745        return anyLeft;
746    } else if (type == 1) {
747        // normal
748        double cutoff = baseModel->getCutoff();
749        CbcNode * node = baseModel->tree()->bestNode(cutoff) ;
750        // Possible one on tree worse than cutoff
751        if (!node || node->objectiveValue() > cutoff)
752            return 1;
753        threadStats_[0]++;
754        //need to think
755        int iThread;
756        // Start one off if any available
757        for (iThread = 0; iThread < numberThreads_; iThread++) {
758            if (children_[iThread].returnCode() == -1)
759                break;
760        }
761        if (iThread < numberThreads_) {
762            children_[iThread].setNode(node);
763#ifdef THREAD_PRINT
764            printf("empty thread %d node %x\n", iThread, children_[iThread].node());
765#endif
766            assert (children_[iThread].returnCode() == -1);
767            // say in use
768            threadModel_[iThread]->moveToModel(baseModel, 0);
769            // This has to be AFTER moveToModel
770            children_[iThread].setReturnCode( 0);
771            children_[iThread].signal();
772            threadCount_[iThread]++;
773        }
774        lockThread();
775        // see if any finished
776        for (iThread = 0; iThread < numberThreads_; iThread++) {
777            if (children_[iThread].returnCode() > 0)
778                break;
779        }
780        unlockThread();
781        if (iThread < numberThreads_) {
782            threadModel_[iThread]->moveToModel(baseModel, 1);
783#ifdef THREAD_PRINT
784            printf("off thread4 %d node %x\n", iThread, children_[iThread].node());
785#endif
786            children_[iThread].setNode(NULL);
787            anyLeft = 1;
788            assert (children_[iThread].returnCode() == 1);
789            // say available
790            children_[iThread].setReturnCode( -1);
791            // carry on
792            threadStats_[3]++;
793        } else {
794            // Start one off if any available
795            for (iThread = 0; iThread < numberThreads_; iThread++) {
796                if (children_[iThread].returnCode() == -1)
797                    break;
798            }
799            if (iThread < numberThreads_) {
800                // If any on tree get
801                if (!baseModel->tree()->empty()) {
802                    //node = baseModel->tree()->bestNode(cutoff) ;
803                    //assert (node);
804                    threadStats_[1]++;
805                    return 1; // ** get another node
806                }
807            }
808            // wait (for debug could sleep and use test)
809            bool finished = false;
810            while (!finished) {
811                double time = getTime();
812                children_[numberThreads_].wait(0, 0);
813                children_[numberThreads_].incrementTimeInThread(getTime() - time);
814                for (iThread = 0; iThread < numberThreads_; iThread++) {
815                    if (children_[iThread].returnCode() > 0) {
816                        finished = true;
817                        break;
818                    } else if (children_[iThread].returnCode() == 0) {
819                        children_[iThread].signal(); // unlock
820                    }
821                }
822            }
823            assert (iThread < numberThreads_);
824            // move information to model
825            threadModel_[iThread]->moveToModel(baseModel, 1);
826            anyLeft = 1;
827#ifdef THREAD_PRINT
828            printf("off thread %d node %x\n", iThread, children_[iThread].node());
829#endif
830            children_[iThread].setNode(NULL);
831            assert (children_[iThread].returnCode() == 1);
832            // say available
833            children_[iThread].setReturnCode( -1);
834        }
835        // carry on
836        threadStats_[2]++;
837        for (int iThread = 0; iThread < numberThreads_; iThread++) {
838            if (children_[iThread].status()) {
839                if (children_[iThread].returnCode() != -1) {
840                    anyLeft = 1;
841                    break;
842                }
843            }
844        }
845        return anyLeft;
846    } else if (type == 2) {
847        if (!baseModel->tree()->empty()) {
848          // max nodes ?
849          bool finished = false;
850          while (!finished) {
851            finished = true;
852            for (int iThread = 0; iThread < numberThreads_; iThread++) {
853              if (children_[iThread].returnCode() == 0) { 
854                double time = getTime();
855                children_[numberThreads_].wait(0, 0);
856                children_[numberThreads_].incrementTimeInThread(getTime() - time);
857                finished = false;
858                children_[iThread].signal(); // unlock
859              }
860            }
861          }
862        }
863        int i;
864        // do statistics
865        // Seems to be bug in CoinCpu on Linux - does threads as well despite documentation
866        double time = 0.0;
867        for (i = 0; i < numberThreads_; i++)
868            time += children_[i].timeInThread();
869        bool goodTimer = time < (baseModel->getCurrentSeconds());
870        for (i = 0; i < numberThreads_; i++) {
871            while (children_[i].returnCode() == 0) {
872                children_[i].signal();
873                double time = getTime();
874                children_[numberThreads_].wait(0, 0);
875                children_[numberThreads_].incrementTimeInThread(getTime() - time);
876            }
877            children_[i].lockFromMaster();
878            threadModel_[i]->setNumberThreads(0); // say exit
879            if (children_[i].deterministic() > 0)
880                delete [] children_[i].delNode();
881            children_[i].setReturnCode( 0);
882            children_[i].unlockFromMaster();
883#ifndef NDEBUG
884            int returnCode = children_[i].exit();
885            assert (!returnCode);
886#else
887            children_[i].exit();
888#endif
889            children_[i].setStatus( 0);
890            //else
891            threadModel_[i]->moveToModel(baseModel, 2);
892            assert (children_[i].numberTimesLocked() == children_[i].numberTimesUnlocked());
893            baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
894            << "Thread";
895            baseModel->messageHandler()->printing(true)
896            << i << threadCount_[i] << children_[i].timeWaitingToStart();
897            baseModel->messageHandler()->printing(goodTimer) << children_[i].timeInThread();
898            baseModel->messageHandler()->printing(false) << 0.0;
899            baseModel->messageHandler()->printing(true) << children_[i].numberTimesLocked()
900            << children_[i].timeLocked() << children_[i].timeWaitingToLock()
901            << CoinMessageEol;
902        }
903        assert (children_[numberThreads_].numberTimesLocked() == children_[numberThreads_].numberTimesUnlocked());
904        baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
905        << "Main thread";
906        baseModel->messageHandler()->printing(false) << 0 << 0 << 0.0;
907        baseModel->messageHandler()->printing(false) << 0.0;
908        baseModel->messageHandler()->printing(true) << children_[numberThreads_].timeInThread();
909        baseModel->messageHandler()->printing(true) << children_[numberThreads_].numberTimesLocked()
910        << children_[numberThreads_].timeLocked() << children_[numberThreads_].timeWaitingToLock()
911        << CoinMessageEol;
912        // delete models (here in case some point to others)
913        for (i = 0; i < numberThreads_; i++) {
914            // make sure handler will be deleted
915            threadModel_[i]->setDefaultHandler(true);
916            //delete threadModel_[i];
917        }
918    } else {
919        abort();
920    }
921    return 0;
922}
923void
924CbcBaseModel::waitForThreadsInCuts(int type, OsiCuts * eachCuts,
925                                   int whichGenerator)
926{
927    if (type == 0) {
928        // cuts while doing
929        bool finished = false;
930        int iThread = -1;
931        // see if any available
932        for (iThread = 0; iThread < numberThreads_; iThread++) {
933            if (children_[iThread].returnCode()) {
934                finished = true;
935                break;
936            } else if (children_[iThread].returnCode() == 0) {
937                children_[iThread].signal();
938            }
939        }
940        while (!finished) {
941            children_[numberThreads_].waitNano(1000000);
942            for (iThread = 0; iThread < numberThreads_; iThread++) {
943                if (children_[iThread].returnCode() > 0) {
944                    finished = true;
945                    break;
946                } else if (children_[iThread].returnCode() == 0) {
947                    children_[iThread].signal();
948                }
949            }
950        }
951        assert (iThread < numberThreads_);
952        assert (children_[iThread].returnCode());
953        // Use dantzigState to signal which generator
954        children_[iThread].setDantzigState(whichGenerator);
955        // and delNode for eachCuts
956        children_[iThread].fakeDelNode(reinterpret_cast<CbcNode **> (eachCuts));
957        // allow to start
958        children_[iThread].setReturnCode( 0);
959        children_[iThread].signal();
960    } else if (type == 1) {
961        // cuts - finish up
962        for (int iThread = 0; iThread < numberThreads_; iThread++) {
963            if (children_[iThread].returnCode() == 0) {
964                bool finished = false;
965                while (!finished) {
966                    children_[numberThreads_].wait(0, 0);
967                    if (children_[iThread].returnCode() > 0) {
968                        finished = true;
969                        break;
970                        //#ifndef NEW_STYLE_PTHREAD
971                        //} else if (children_[iThread].returnCode_ == 0) {
972                        //pthread_cond_signal(&children_[iThread].threadStuff_.condition2_); // unlock
973                        //#endif
974                    }
975                }
976            }
977            assert (children_[iThread].returnCode());
978            // say available
979            children_[iThread].setReturnCode( -1);
980            //delete threadModel_[iThread]->solver();
981            //threadModel_[iThread]->setSolver(NULL);
982        }
983    } else {
984        abort();
985    }
986}
987// Returns pointer to master thread
988CbcThread *
989CbcBaseModel::masterThread() const
990{
991    return children_ + numberThreads_;
992}
993
994// Split model and do work in deterministic parallel
995void
996CbcBaseModel::deterministicParallel()
997{
998    CbcModel * baseModel = children_[0].baseModel();
999    for (int i = 0; i < numberThreads_; i++)
1000        threadCount_[i]++;
1001    int saveTreeSize = baseModel->tree()->size();
1002    // For now create threadModel - later modify splitModel
1003    CbcModel ** threadModel = new CbcModel * [numberThreads_];
1004    int iThread;
1005    for (iThread = 0; iThread < numberThreads_; iThread++)
1006        threadModel[iThread] = children_[iThread].thisModel();
1007
1008    int nAffected = baseModel->splitModel(numberThreads_, threadModel, defaultParallelNodes_);
1009    // do all until finished
1010    for (iThread = 0; iThread < numberThreads_; iThread++) {
1011        // obviously tune
1012        children_[iThread].setNDeleteNode(defaultParallelIterations_);
1013    }
1014    // Save current state
1015    int iObject;
1016    OsiObject ** object = baseModel->objects();
1017    for (iObject = 0; iObject < numberObjects_; iObject++) {
1018        saveObjects_[iObject]->updateBefore(object[iObject]);
1019    }
1020    //#define FAKE_PARALLEL
1021#ifndef FAKE_PARALLEL
1022    for (iThread = 0; iThread < numberThreads_; iThread++) {
1023        children_[iThread].setReturnCode( 0);
1024        children_[iThread].signal();
1025    }
1026    // wait
1027    bool finished = false;
1028    double time = getTime();
1029    while (!finished) {
1030        children_[numberThreads_].waitNano( 1000000); // millisecond
1031        finished = true;
1032        for (iThread = 0; iThread < numberThreads_; iThread++) {
1033            if (children_[iThread].returnCode() <= 0) {
1034                finished = false;
1035            }
1036        }
1037    }
1038    for (iThread = 0; iThread < numberThreads_; iThread++)
1039        children_[iThread].setReturnCode(-1);
1040#else
1041    // wait
1042    bool finished = false;
1043    double time = getTime();
1044    for (iThread = 0; iThread < numberThreads_; iThread++) {
1045        children_[iThread].setReturnCode( 0);
1046        children_[iThread].signal();
1047        while (!finished) {
1048          children_[numberThreads_].waitNano( 1000000); // millisecond
1049          finished = (children_[iThread].returnCode() >0);
1050        }
1051        children_[iThread].setReturnCode(-1);
1052        finished=false;
1053    }
1054#endif
1055    children_[numberThreads_].incrementTimeInThread(getTime() - time);
1056    // Unmark marked
1057    for (int i = 0; i < nAffected; i++) {
1058        baseModel->walkback()[i]->unmark();
1059    }
1060    int iModel;
1061    double scaleFactor = 1.0;
1062    for (iModel = 0; iModel < numberThreads_; iModel++) {
1063        //printf("model %d tree size %d\n",iModel,threadModel[iModel]->baseModel->tree()->size());
1064        if (saveTreeSize > 4*numberThreads_*defaultParallelNodes_) {
1065            if (!threadModel[iModel]->tree()->size()) {
1066                scaleFactor *= 1.05;
1067            }
1068        }
1069        threadModel[iModel]->moveToModel(baseModel, 11);
1070        // Update base model
1071        OsiObject ** threadObject = threadModel[iModel]->objects();
1072        for (iObject = 0; iObject < numberObjects_; iObject++) {
1073            object[iObject]->updateAfter(threadObject[iObject], saveObjects_[iObject]);
1074        }
1075    }
1076    if (scaleFactor != 1.0) {
1077        int newNumber = static_cast<int> (defaultParallelNodes_ * scaleFactor + 0.5001);
1078        if (newNumber*2 < defaultParallelIterations_) {
1079            if (defaultParallelNodes_ == 1)
1080                newNumber = 2;
1081            if (newNumber != defaultParallelNodes_) {
1082                char general[200];
1083                sprintf(general, "Changing tree size from %d to %d",
1084                        defaultParallelNodes_, newNumber);
1085                baseModel->messageHandler()->message(CBC_GENERAL,
1086                                                     baseModel->messages())
1087                << general << CoinMessageEol ;
1088                defaultParallelNodes_ = newNumber;
1089            }
1090        }
1091    }
1092    delete [] threadModel;
1093}
1094// Destructor
1095CbcBaseModel::~CbcBaseModel()
1096{
1097    delete [] threadCount_;
1098#if 1
1099    for (int i = 0; i < numberThreads_; i++)
1100        delete threadModel_[i];
1101    delete [] threadModel_;
1102    delete [] children_;
1103#endif
1104    for (int i = 0; i < numberObjects_; i++)
1105        delete saveObjects_[i];
1106    delete [] saveObjects_;
1107}
1108// Sets Dantzig state in children
1109void
1110CbcBaseModel::setDantzigState()
1111{
1112    for (int i = 0; i < numberThreads_; i++) {
1113        children_[i].setDantzigState(-1);
1114    }
1115}
1116static void * doNodesThread(void * voidInfo)
1117{
1118    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1119    CbcModel * thisModel = stuff->thisModel();
1120    CbcModel * baseModel = stuff->baseModel();
1121    while (true) {
1122        stuff->waitThread();
1123        //printf("start node %x\n",stuff->node);
1124        int mode = thisModel->getNumberThreads();
1125        if (mode) {
1126            // normal
1127            double time2 = CoinCpuTime();
1128            assert (stuff->returnCode() == 0);
1129            if (thisModel->parallelMode() >= 0) {
1130                CbcNode * node = stuff->node();
1131                //assert (node->nodeInfo());
1132                CbcNode * createdNode = stuff->createdNode();
1133                // try and see if this has slipped through
1134                if (node) {
1135                  thisModel->doOneNode(baseModel, node, createdNode);
1136                } else {
1137                  //printf("null node\n");
1138                  createdNode=NULL;
1139                }
1140                stuff->setNode(node);
1141                stuff->setCreatedNode(createdNode);
1142                stuff->setReturnCode( 1);
1143            } else {
1144                assert (!stuff->node());
1145                assert (!stuff->createdNode());
1146                int numberIterations = stuff->nDeleteNode();
1147                int nDeleteNode = 0;
1148                int maxDeleteNode = stuff->maxDeleteNode();
1149                CbcNode ** delNode = stuff->delNode();
1150                int returnCode = 1;
1151                // this should be updated by heuristics strong branching etc etc
1152                assert (numberIterations > 0);
1153                thisModel->setNumberThreads(0);
1154                int nodesThisTime = thisModel->getNodeCount();
1155                int iterationsThisTime = thisModel->getIterationCount();
1156                int strongThisTime = thisModel->numberStrongIterations();
1157                thisModel->setStopNumberIterations(thisModel->getIterationCount() + numberIterations);
1158                int numberColumns = thisModel->getNumCols();
1159                int * used = CoinCopyOfArray(thisModel->usedInSolution(), numberColumns);
1160                int numberSolutions = thisModel->getSolutionCount();
1161                while (true) {
1162                    if (thisModel->tree()->empty()) {
1163                        returnCode = 1 + 1;
1164#ifdef CLP_INVESTIGATE_2
1165                        printf("%x tree empty - time %18.6f\n", thisModel, CoinGetTimeOfDay() - 1.2348e9);
1166#endif
1167                        break;
1168                    }
1169#define NODE_ITERATIONS 2
1170                    int nodesNow = thisModel->getNodeCount();
1171                    int iterationsNow = thisModel->getIterationCount();
1172                    int strongNow = thisModel->numberStrongIterations();
1173                    bool exit1 = (NODE_ITERATIONS * ((nodesNow - nodesThisTime) +
1174                                                     ((strongNow - strongThisTime) >> 1)) +
1175                                  (iterationsNow - iterationsThisTime) > numberIterations);
1176                    //bool exit2 =(thisModel->getIterationCount()>thisModel->getStopNumberIterations()) ;
1177                    //assert (exit1==exit2);
1178                    if (exit1 && nodesNow - nodesThisTime >= 10) {
1179                        // out of loop
1180                        //printf("out of loop\n");
1181#ifdef CLP_INVESTIGATE3
1182                        printf("%x tree %d nodes left, done %d and %d its - time %18.6f\n", thisModel,
1183                               thisModel->tree()->size(), nodesNow - nodesThisTime,
1184                               iterationsNow - iterationsThisTime, CoinGetTimeOfDay() - 1.2348e9);
1185#endif
1186                        break;
1187                    }
1188                    double cutoff = thisModel->getCutoff() ;
1189                    CbcNode *node = thisModel->tree()->bestNode(cutoff) ;
1190                    // Possible one on tree worse than cutoff
1191                    if (!node)
1192                        continue;
1193                    CbcNode * createdNode = NULL;
1194                    // Do real work of node
1195                    thisModel->doOneNode(NULL, node, createdNode);
1196                    assert (createdNode);
1197                    if (!createdNode->active()) {
1198                        delete createdNode;
1199                    } else {
1200                        // Say one more pointing to this **** postpone if marked
1201                        node->nodeInfo()->increment() ;
1202                        thisModel->tree()->push(createdNode) ;
1203                    }
1204                    if (node->active()) {
1205                        assert (node->nodeInfo());
1206                        if (node->nodeInfo()->numberBranchesLeft()) {
1207                            thisModel->tree()->push(node) ;
1208                        } else {
1209                            node->setActive(false);
1210                        }
1211                    } else {
1212                        if (node->nodeInfo()) {
1213                            if (!node->nodeInfo()->numberBranchesLeft())
1214                                node->nodeInfo()->allBranchesGone(); // can clean up
1215                            // So will delete underlying stuff
1216                            node->setActive(true);
1217                        }
1218                        if (nDeleteNode == maxDeleteNode) {
1219                            maxDeleteNode = (3 * maxDeleteNode) / 2 + 10;
1220                            stuff->setMaxDeleteNode(maxDeleteNode);
1221                            stuff->setDelNode(new CbcNode * [maxDeleteNode]);
1222                            for (int i = 0; i < nDeleteNode; i++)
1223                                stuff->delNode()[i] = delNode[i];
1224                            delete [] delNode;
1225                            delNode = stuff->delNode();
1226                        }
1227                        delNode[nDeleteNode++] = node;
1228                    }
1229                }
1230                // end of this sub-tree
1231                int * usedA = thisModel->usedInSolution();
1232                for (int i = 0; i < numberColumns; i++) {
1233                    usedA[i] -= used[i];
1234                }
1235                delete [] used;
1236                thisModel->setSolutionCount(thisModel->getSolutionCount() - numberSolutions);
1237                stuff->setNodesThisTime(thisModel->getNodeCount() - nodesThisTime);
1238                stuff->setIterationsThisTime(thisModel->getIterationCount() - iterationsThisTime);
1239                stuff->setNDeleteNode(nDeleteNode);
1240                stuff->setReturnCode( returnCode);
1241                thisModel->setNumberThreads(mode);
1242            }
1243            //printf("end node %x\n",stuff->node);
1244            stuff->unlockFromThread();
1245            stuff->incrementTimeInThread(CoinCpuTime() - time2);
1246        } else {
1247            // exit
1248            break;
1249        }
1250    }
1251    //printf("THREAD exiting\n");
1252    stuff->exitThread();
1253    return NULL;
1254}
1255static void * doHeurThread(void * voidInfo)
1256{
1257    typedef struct {
1258        double solutionValue;
1259        CbcModel * model;
1260        double * solution;
1261        int foundSol;
1262    } argBundle;
1263    argBundle * stuff = reinterpret_cast<argBundle *> (voidInfo);
1264    stuff->foundSol =
1265        stuff->model->heuristic(0)->solution(stuff->solutionValue,
1266                                             stuff->solution);
1267    return NULL;
1268}
1269static void * doCutsThread(void * voidInfo)
1270{
1271    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
1272    CbcModel * thisModel =  stuff->thisModel();
1273    while (true) {
1274        stuff->waitThread();
1275        //printf("start node %x\n",stuff->node);
1276        int mode = thisModel->getNumberThreads();
1277        if (mode) {
1278            // normal
1279            assert (stuff->returnCode() == 0);
1280            int fullScan = thisModel->getNodeCount() == 0 ? 1 : 0; //? was >0
1281            CbcCutGenerator * generator = thisModel->cutGenerator(stuff->dantzigState());
1282            generator->refreshModel(thisModel);
1283            OsiCuts * cuts = reinterpret_cast<OsiCuts *> (stuff->delNode());
1284            OsiSolverInterface * thisSolver = thisModel->solver();
1285            generator->generateCuts(*cuts, fullScan, thisSolver, NULL);
1286            stuff->setReturnCode( 1);
1287            stuff->unlockFromThread();
1288        } else {
1289            // exit
1290            break;
1291        }
1292    }
1293    stuff->exitThread();
1294    return NULL;
1295}
1296// Split up nodes - returns number of CbcNodeInfo's affected
1297int
1298CbcModel::splitModel(int numberModels, CbcModel ** model,
1299                     int numberNodes)
1300{
1301    int iModel;
1302    int i;
1303    for (iModel = 0; iModel < numberModels; iModel++) {
1304        CbcModel * otherModel = model[iModel];
1305        otherModel->moveToModel(this, 10);
1306        assert (!otherModel->tree()->size());
1307        otherModel->tree()->resetNodeNumbers();
1308        otherModel->bestPossibleObjective_ = bestPossibleObjective_;
1309        otherModel->sumChangeObjective1_ = sumChangeObjective1_;
1310        otherModel->sumChangeObjective2_ = sumChangeObjective2_;
1311        int numberColumns = solver_->getNumCols();
1312        if (otherModel->bestSolution_) {
1313            assert (bestSolution_);
1314            memcpy(otherModel->bestSolution_, bestSolution_, numberColumns*sizeof(double));
1315        } else if (bestSolution_) {
1316            otherModel->bestSolution_ = CoinCopyOfArray(bestSolution_, numberColumns);
1317        }
1318        otherModel->globalCuts_ = globalCuts_;
1319        otherModel->numberSolutions_ = numberSolutions_;
1320        otherModel->numberHeuristicSolutions_ = numberHeuristicSolutions_;
1321        otherModel->numberNodes_ = numberNodes_;
1322        otherModel->numberIterations_ = numberIterations_;
1323#ifdef JJF_ZERO
1324        if (maximumNumberCuts_ > otherModel->maximumNumberCuts_) {
1325            otherModel->maximumNumberCuts_ = maximumNumberCuts_;
1326            delete [] otherModel->addedCuts_;
1327            otherModel->addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
1328        }
1329        if (maximumDepth_ > otherModel->maximumDepth_) {
1330            otherModel->maximumDepth_ = maximumDepth_;
1331            delete [] otherModel->walkback_;
1332            otherModel->walkback_ = new CbcNodeInfo * [maximumDepth_];
1333        }
1334#endif
1335        otherModel->currentNumberCuts_ = currentNumberCuts_;
1336        if (otherModel->usedInSolution_) {
1337            assert (usedInSolution_);
1338            memcpy(otherModel->usedInSolution_, usedInSolution_, numberColumns*sizeof(int));
1339        } else if (usedInSolution_) {
1340            otherModel->usedInSolution_ = CoinCopyOfArray(usedInSolution_, numberColumns);
1341        }
1342        /// ??? tree_;
1343        // Need flag (stopNumberIterations_>0?) which says don't update cut etc counts
1344        for (i = 0; i < numberObjects_; i++) {
1345            otherModel->object_[i]->updateBefore(object_[i]);
1346        }
1347        otherModel->maximumDepthActual_ = maximumDepthActual_;
1348        // Real cuts are in node info
1349        otherModel->numberOldActiveCuts_ = numberOldActiveCuts_;
1350        otherModel->numberNewCuts_ = numberNewCuts_;
1351        otherModel->numberStrongIterations_ = numberStrongIterations_;
1352    }
1353    double cutoff = getCutoff();
1354    int nAffected = 0;
1355    while (!tree_->empty()) {
1356        for (iModel = 0; iModel < numberModels; iModel++) {
1357            if (tree_->empty())
1358                break;
1359            CbcModel * otherModel = model[iModel];
1360            CbcNode * node = tree_->bestNode(cutoff) ;
1361            CbcNodeInfo * nodeInfo = node->nodeInfo();
1362            assert (nodeInfo);
1363            if (!nodeInfo->marked()) {
1364                //while (nodeInfo&&!nodeInfo->marked()) {
1365                if (nAffected == maximumDepth_) {
1366                    redoWalkBack();
1367                }
1368                nodeInfo->mark();
1369                //nodeInfo->incrementCuts(1000000);
1370                walkback_[nAffected++] = nodeInfo;
1371                //nodeInfo = nodeInfo->parent() ;
1372                //}
1373            }
1374            // Make node join otherModel
1375            OsiBranchingObject * bobj = node->modifiableBranchingObject();
1376            CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1377            //assert (cbcobj);
1378            if (cbcobj) {
1379                CbcObject * object = cbcobj->object();
1380                assert (object);
1381                int position = object->position();
1382                assert (position >= 0);
1383                assert (object_[position] == object);
1384                CbcObject * objectNew =
1385                    dynamic_cast<CbcObject *> (otherModel->object_[position]);
1386                cbcobj->setOriginalObject(objectNew);
1387            }
1388            otherModel->tree_->push(node);
1389        }
1390        numberNodes--;
1391        if (!numberNodes)
1392            break;
1393    }
1394    return nAffected;
1395}
1396// Start threads
1397void
1398CbcModel::startSplitModel(int /*numberIterations*/)
1399{
1400    abort();
1401}
1402// Merge models
1403void
1404CbcModel::mergeModels(int /*numberModel*/, CbcModel ** /*model*/,
1405                      int /*numberNodes*/)
1406{
1407    abort();
1408}
1409/* Move/copy information from one model to another
1410   -1 - initial setup
1411   0 - from base model
1412   1 - to base model (and reset)
1413   2 - add in final statistics etc (and reset so can do clean destruction)
1414   10 - from base model (deterministic)
1415   11 - to base model (deterministic)
1416*/
1417void
1418CbcModel::moveToModel(CbcModel * baseModel, int mode)
1419{
1420    if (mode == 0) {
1421        setCutoff(baseModel->getCutoff());
1422        bestObjective_ = baseModel->bestObjective_;
1423        //assert (!baseModel->globalCuts_.sizeRowCuts());
1424        if (numberSolutions_ < baseModel->numberSolutions_&& baseModel->bestSolution_) {
1425          int numberColumns = solver_->getNumCols();
1426          if (!bestSolution_)
1427            bestSolution_ = new double [numberColumns];
1428          memcpy(bestSolution_,baseModel->bestSolution_,
1429                 numberColumns*sizeof(double));
1430          numberSolutions_ = baseModel->numberSolutions_;
1431        }
1432        stateOfSearch_ = baseModel->stateOfSearch_;
1433        numberNodes_ = baseModel->numberNodes_;
1434        numberIterations_ = baseModel->numberIterations_;
1435        numberFixedAtRoot_ = numberIterations_; // for statistics
1436        numberSolves_ = 0;
1437        phase_ = baseModel->phase_;
1438        assert (!nextRowCut_);
1439        nodeCompare_ = baseModel->nodeCompare_;
1440        tree_ = baseModel->tree_;
1441        assert (!subTreeModel_);
1442        //branchingMethod_ = NULL; // need something but what
1443        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1444        cutModifier_ = NULL;
1445        assert (!analyzeResults_);
1446        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1447        assert (stuff);
1448        //if (stuff)
1449        stuff->setCreatedNode(NULL);
1450        // ?? searchStrategy_;
1451        searchStrategy_ = baseModel->searchStrategy_;
1452        stuff->saveStuff()[0] = searchStrategy_;
1453        stateOfSearch_ = baseModel->stateOfSearch_;
1454        stuff->saveStuff()[1] = stateOfSearch_;
1455        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1456            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
1457                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
1458            if (dynamicObject) {
1459                CbcSimpleIntegerDynamicPseudoCost * baseObject =
1460                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(baseModel->object_[iObject]) ;
1461                assert (baseObject);
1462                dynamicObject->copySome(baseObject);
1463            }
1464        }
1465    } else if (mode == 1) {
1466        lockThread();
1467        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1468        assert (stuff);
1469        //stateOfSearch_
1470        if (stuff->saveStuff()[0] != searchStrategy_) {
1471#ifdef COIN_DEVELOP
1472            printf("changing searchStrategy from %d to %d\n",
1473                   baseModel->searchStrategy_, searchStrategy_);
1474#endif
1475            baseModel->searchStrategy_ = searchStrategy_;
1476        }
1477        if (stuff->saveStuff()[1] != stateOfSearch_) {
1478#ifdef COIN_DEVELOP
1479            printf("changing stateOfSearch from %d to %d\n",
1480                   baseModel->stateOfSearch_, stateOfSearch_);
1481#endif
1482            baseModel->stateOfSearch_ = stateOfSearch_;
1483        }
1484        if (numberUpdateItems_) {
1485            for (int i = 0; i < numberUpdateItems_; i++) {
1486                CbcObjectUpdateData * update = updateItems_ + i;
1487                int objectNumber = update->objectNumber_;
1488                CbcObject * object = dynamic_cast<CbcObject *> (baseModel->object_[objectNumber]);
1489                if (object)
1490                    object->updateInformation(*update);
1491            }
1492            numberUpdateItems_ = 0;
1493        }
1494        if (eventHappened_)
1495            baseModel->eventHappened_ = true;
1496        baseModel->numberNodes_++;
1497        baseModel->numberIterations_ +=
1498            numberIterations_ - numberFixedAtRoot_;
1499        baseModel->numberSolves_ += numberSolves_;
1500        if (stuff->node())
1501            baseModel->tree_->push(stuff->node());
1502        if (stuff->createdNode())
1503            baseModel->tree_->push(stuff->createdNode());
1504        unlockThread();
1505    } else if (mode == 2) {
1506        baseModel->sumChangeObjective1_ += sumChangeObjective1_;
1507        baseModel->sumChangeObjective2_ += sumChangeObjective2_;
1508        //baseModel->numberIterations_ += numberIterations_;
1509        for (int iGenerator = 0; iGenerator < numberCutGenerators_; iGenerator++) {
1510            CbcCutGenerator * generator = baseModel->generator_[iGenerator];
1511            CbcCutGenerator * generator2 = generator_[iGenerator];
1512            generator->incrementNumberTimesEntered(generator2->numberTimesEntered());
1513            generator->incrementNumberCutsInTotal(generator2->numberCutsInTotal());
1514            generator->incrementNumberCutsActive(generator2->numberCutsActive());
1515            generator->incrementTimeInCutGenerator(generator2->timeInCutGenerator());
1516        }
1517        if (parallelMode() >= 0)
1518            nodeCompare_ = NULL;
1519        baseModel->maximumDepthActual_ = CoinMax(baseModel->maximumDepthActual_, maximumDepthActual_);
1520        baseModel->numberDJFixed_ += numberDJFixed_;
1521        baseModel->numberStrongIterations_ += numberStrongIterations_;
1522        int i;
1523        for (i = 0; i < 3; i++)
1524            baseModel->strongInfo_[i] += strongInfo_[i];
1525        if (parallelMode() >= 0) {
1526            walkback_ = NULL;
1527            lastNodeInfo_ = NULL;
1528            lastNumberCuts_ = NULL;
1529            lastCut_ = NULL;
1530            //addedCuts_ = NULL;
1531            tree_ = NULL;
1532        }
1533        if ((moreSpecialOptions2_&32)!=0)
1534          delete eventHandler_;
1535        eventHandler_ = NULL;
1536        delete solverCharacteristics_;
1537        solverCharacteristics_ = NULL;
1538        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1539        if (newMethod) {
1540            // new method - we were using base models
1541            numberObjects_ = 0;
1542            object_ = NULL;
1543        }
1544    } else if (mode == -1) {
1545        delete eventHandler_;
1546        if ((moreSpecialOptions2_&32)==0||!baseModel->eventHandler_) {
1547          eventHandler_ = baseModel->eventHandler_;
1548        } else {
1549          eventHandler_ = baseModel->eventHandler_->clone();
1550          eventHandler_->setModel(this);
1551        }
1552        assert (!statistics_);
1553        assert(baseModel->solverCharacteristics_);
1554        solverCharacteristics_ = new OsiBabSolver (*baseModel->solverCharacteristics_);
1555        solverCharacteristics_->setSolver(solver_);
1556        setMaximumNodes(COIN_INT_MAX);
1557        if (parallelMode() >= 0) {
1558            delete [] walkback_;
1559            //delete [] addedCuts_;
1560            walkback_ = NULL;
1561            //addedCuts_ = NULL;
1562            delete [] lastNodeInfo_ ;
1563            lastNodeInfo_ = NULL;
1564            delete [] lastNumberCuts_ ;
1565            lastNumberCuts_ = NULL;
1566            delete [] lastCut_ ;
1567            lastCut_ = NULL;
1568            delete tree_;
1569            tree_ = NULL;
1570            delete nodeCompare_;
1571            nodeCompare_ = NULL;
1572        } else {
1573            delete tree_;
1574            tree_ = new CbcTree();
1575            tree_->setComparison(*nodeCompare_) ;
1576        }
1577        continuousSolver_ = baseModel->continuousSolver_->clone();
1578        // make sure solvers have correct message handler
1579        solver_->passInMessageHandler(handler_);
1580        continuousSolver_->passInMessageHandler(handler_);
1581        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
1582        if (newMethod) {
1583            // new method uses solver - but point to base model
1584            // We may update an object in wrong order - shouldn't matter?
1585            numberObjects_ = baseModel->numberObjects_;
1586            if (parallelMode() >= 0) {
1587                object_ = baseModel->object_;
1588            } else {
1589                printf("*****WARNING - fix testosi option\n");
1590                object_ = baseModel->object_;
1591            }
1592        }
1593        int i;
1594        for (i = 0; i < numberHeuristics_; i++) {
1595            delete heuristic_[i];
1596            heuristic_[i] = baseModel->heuristic_[i]->clone();
1597            heuristic_[i]->setModelOnly(this);
1598        }
1599        for (i = 0; i < numberCutGenerators_; i++) {
1600            delete generator_[i];
1601            generator_[i] = new CbcCutGenerator(*baseModel->generator_[i]);
1602            // refreshModel was overkill as thought too many rows
1603            if (generator_[i]->needsRefresh())
1604              generator_[i]->refreshModel(this);
1605            else
1606              generator_[i]->setModel(this);
1607        }
1608    } else if (mode == 10) {
1609        setCutoff(baseModel->getCutoff());
1610        bestObjective_ = baseModel->bestObjective_;
1611        //assert (!baseModel->globalCuts_.sizeRowCuts());
1612        numberSolutions_ = baseModel->numberSolutions_;
1613        assert (usedInSolution_);
1614        assert (baseModel->usedInSolution_);
1615        memcpy(usedInSolution_, baseModel->usedInSolution_, solver_->getNumCols()*sizeof(int));
1616        stateOfSearch_ = baseModel->stateOfSearch_;
1617        //numberNodes_ = baseModel->numberNodes_;
1618        //numberIterations_ = baseModel->numberIterations_;
1619        //numberFixedAtRoot_ = numberIterations_; // for statistics
1620        phase_ = baseModel->phase_;
1621        assert (!nextRowCut_);
1622        delete nodeCompare_;
1623        nodeCompare_ = baseModel->nodeCompare_->clone();
1624        tree_->setComparison(*nodeCompare_) ;
1625        assert (!subTreeModel_);
1626        //branchingMethod_ = NULL; // need something but what
1627        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
1628        cutModifier_ = NULL;
1629        assert (!analyzeResults_);
1630        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1631        assert (stuff);
1632        //if (stuff)
1633        stuff->setCreatedNode(NULL);
1634        // ?? searchStrategy_;
1635        searchStrategy_ = baseModel->searchStrategy_;
1636        stuff->saveStuff()[0] = searchStrategy_;
1637        stateOfSearch_ = baseModel->stateOfSearch_;
1638        stuff->saveStuff()[1] = stateOfSearch_;
1639        OsiObject ** baseObject = baseModel->object_;
1640        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
1641            object_[iObject]->updateBefore(baseObject[iObject]);
1642        }
1643        //delete [] stuff->nodeCount;
1644        //stuff->nodeCount = new int [baseModel->maximumDepth_+1];
1645    } else if (mode == 11) {
1646        if (parallelMode() < 0) {
1647            // from deterministic
1648            CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
1649            assert (stuff);
1650            // Move solution etc
1651            // might as well mark all including continuous
1652            int numberColumns = solver_->getNumCols();
1653            for (int i = 0; i < numberColumns; i++) {
1654                baseModel->usedInSolution_[i] += usedInSolution_[i];
1655                //usedInSolution_[i]=0;
1656            }
1657            baseModel->numberSolutions_ += numberSolutions_;
1658            if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
1659                baseModel->bestObjective_ = bestObjective_ ;
1660                int numberColumns = solver_->getNumCols();
1661                if (!baseModel->bestSolution_)
1662                    baseModel->bestSolution_ = new double[numberColumns];
1663                CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
1664                baseModel->setCutoff(getCutoff());
1665                baseModel->handler_->message(CBC_ROUNDING, messages_)
1666                << bestObjective_
1667                << "heuristic"
1668                << baseModel->numberIterations_
1669                << baseModel->numberNodes_ << getCurrentSeconds()
1670                << CoinMessageEol;
1671            }
1672            //stateOfSearch_
1673            if (stuff->saveStuff()[0] != searchStrategy_) {
1674#ifdef COIN_DEVELOP
1675                printf("changing searchStrategy from %d to %d\n",
1676                       baseModel->searchStrategy_, searchStrategy_);
1677#endif
1678                baseModel->searchStrategy_ = searchStrategy_;
1679            }
1680            if (stuff->saveStuff()[1] != stateOfSearch_) {
1681#ifdef COIN_DEVELOP
1682                printf("changing stateOfSearch from %d to %d\n",
1683                       baseModel->stateOfSearch_, stateOfSearch_);
1684#endif
1685                baseModel->stateOfSearch_ = stateOfSearch_;
1686            }
1687            int i;
1688            if (eventHappened_)
1689                baseModel->eventHappened_ = true;
1690            baseModel->numberNodes_ += stuff->nodesThisTime();
1691            baseModel->numberIterations_ += stuff->iterationsThisTime();
1692            double cutoff = baseModel->getCutoff();
1693            while (!tree_->empty()) {
1694                CbcNode * node = tree_->bestNode(COIN_DBL_MAX) ;
1695                if (node->objectiveValue() < cutoff) {
1696                    assert(node->nodeInfo());
1697                    // Make node join correctly
1698                    OsiBranchingObject * bobj = node->modifiableBranchingObject();
1699                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
1700                    if (cbcobj) {
1701                        CbcObject * object = cbcobj->object();
1702                        assert (object);
1703                        int position = object->position();
1704                        assert (position >= 0);
1705                        assert (object_[position] == object);
1706                        CbcObject * objectNew =
1707                            dynamic_cast<CbcObject *> (baseModel->object_[position]);
1708                        cbcobj->setOriginalObject(objectNew);
1709                    }
1710                    baseModel->tree_->push(node);
1711                } else {
1712                    delete node;
1713                }
1714            }
1715            for (i = 0; i < stuff->nDeleteNode(); i++) {
1716                //printf("CbcNode %x stuff delete\n",stuff->delNode[i]);
1717                delete stuff->delNode()[i];
1718            }
1719        }
1720    } else {
1721        abort();
1722    }
1723}
1724// Generate one round of cuts - parallel mode
1725int
1726CbcModel::parallelCuts(CbcBaseModel * master, OsiCuts & theseCuts,
1727                       CbcNode * /*node*/, OsiCuts & slackCuts, int lastNumberCuts)
1728{
1729    /*
1730      Is it time to scan the cuts in order to remove redundant cuts? If so, set
1731      up to do it.
1732    */
1733    int fullScan = 0 ;
1734    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
1735        fullScan = 1 ;
1736        if (!numberNodes_ || (specialOptions_&256) != 0)
1737            fullScan = 2;
1738        specialOptions_ &= ~256; // mark as full scan done
1739    }
1740    // do cuts independently
1741    OsiCuts * eachCuts = new OsiCuts [numberCutGenerators_];;
1742    int i;
1743    assert (master);
1744    for (i = 0; i < numberThreads_; i++) {
1745        // set solver here after cloning
1746        master->model(i)->solver_ = solver_->clone();
1747        master->model(i)->numberNodes_ = (fullScan) ? 1 : 0;
1748    }
1749    // generate cuts
1750    int status = 0;
1751    const OsiRowCutDebugger * debugger = NULL;
1752    bool onOptimalPath = false;
1753    for (i = 0; i < numberCutGenerators_; i++) {
1754        bool generate = generator_[i]->normal();
1755        // skip if not optimal and should be (maybe a cut generator has fixed variables)
1756        if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
1757            generate = false;
1758        if (generator_[i]->switchedOff())
1759            generate = false;;
1760        if (generate) {
1761            master->waitForThreadsInCuts(0, eachCuts + i, i);
1762        }
1763    }
1764    // wait
1765    master->waitForThreadsInCuts(1, eachCuts, 0);
1766    // Now put together
1767    for (i = 0; i < numberCutGenerators_; i++) {
1768        // add column cuts
1769        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
1770        int numberColumnCuts = eachCuts[i].sizeColCuts();
1771        int numberColumnCutsAfter = numberColumnCutsBefore
1772                                    + numberColumnCuts;
1773        int j;
1774        for (j = 0; j < numberColumnCuts; j++) {
1775            theseCuts.insert(eachCuts[i].colCut(j));
1776        }
1777        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
1778        int numberRowCuts = eachCuts[i].sizeRowCuts();
1779        // insert good cuts
1780        if (numberRowCuts) {
1781            int n = numberRowCuts;
1782            numberRowCuts = 0;
1783            for (j = 0; j < n; j++) {
1784                const OsiRowCut * thisCut = eachCuts[i].rowCutPtr(j) ;
1785                if (thisCut->lb() <= 1.0e10 && thisCut->ub() >= -1.0e10) {
1786                    theseCuts.insert(eachCuts[i].rowCut(j));
1787                    numberRowCuts++;
1788                }
1789            }
1790            if (generator_[i]->mustCallAgain() && status >= 0)
1791                status = 1; // say must go round
1792        }
1793        int numberRowCutsAfter = numberRowCutsBefore
1794                                 + numberRowCuts;
1795        if (numberRowCuts) {
1796            // Check last cut to see if infeasible
1797            const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
1798            if (thisCut->lb() > thisCut->ub()) {
1799                status = -1; // sub-problem is infeasible
1800                break;
1801            }
1802        }
1803#ifdef CBC_DEBUG
1804        {
1805            int k ;
1806            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1807                OsiRowCut thisCut = theseCuts.rowCut(k) ;
1808                /* check size of elements.
1809                   We can allow smaller but this helps debug generators as it
1810                   is unsafe to have small elements */
1811                int n = thisCut.row().getNumElements();
1812                const int * column = thisCut.row().getIndices();
1813                const double * element = thisCut.row().getElements();
1814                //assert (n);
1815                for (int i = 0; i < n; i++) {
1816                    double value = element[i];
1817                    assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
1818                }
1819            }
1820        }
1821#endif
1822        if ((specialOptions_&1) != 0) {
1823            if (onOptimalPath) {
1824                int k ;
1825                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
1826                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
1827                    if (debugger->invalidCut(thisCut)) {
1828                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
1829                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
1830#ifdef NDEBUG
1831                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
1832                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
1833                        const double *lower = getColLower() ;
1834                        const double *upper = getColUpper() ;
1835                        int numberColumns = solver_->getNumCols();
1836                        for (int i = 0; i < numberColumns; i++)
1837                            printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
1838                        abort();
1839#endif
1840                    }
1841                    assert(!debugger->invalidCut(thisCut)) ;
1842                }
1843            }
1844        }
1845        /*
1846          The cut generator has done its thing, and maybe it generated some
1847          cuts.  Do a bit of bookkeeping: load
1848          whichGenerator[i] with the index of the generator responsible for a cut,
1849          and place cuts flagged as global in the global cut pool for the model.
1850
1851          lastNumberCuts is the sum of cuts added in previous iterations; it's the
1852          offset to the proper starting position in whichGenerator.
1853        */
1854        int numberBefore =
1855            numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts ;
1856        int numberAfter =
1857            numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts ;
1858        // possibly extend whichGenerator
1859        resizeWhichGenerator(numberBefore, numberAfter);
1860
1861        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
1862            whichGenerator_[numberBefore++] = i ;
1863            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
1864            if (thisCut->lb() > thisCut->ub())
1865                status = -1; // sub-problem is infeasible
1866            if (thisCut->globallyValid()) {
1867                // add to global list
1868                OsiRowCut newCut(*thisCut);
1869                newCut.setGloballyValid(true);
1870                newCut.mutableRow().setTestForDuplicateIndex(false);
1871                globalCuts_.addCutIfNotDuplicate(newCut) ;
1872            }
1873        }
1874        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
1875            //whichGenerator_[numberBefore++] = i ;
1876            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
1877            if (thisCut->globallyValid()) {
1878                // add to global list
1879                makeGlobalCut(thisCut);
1880            }
1881        }
1882    }
1883    // Add in any violated saved cuts
1884    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
1885        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
1886        int numberCuts = slackCuts.sizeRowCuts() ;
1887        int i;
1888        // possibly extend whichGenerator
1889        resizeWhichGenerator(numberOld, numberOld + numberCuts);
1890        double primalTolerance;
1891        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
1892        for ( i = 0; i < numberCuts; i++) {
1893            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
1894            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
1895                if (messageHandler()->logLevel() > 2)
1896                    printf("Old cut added - violation %g\n",
1897                           thisCut->violated(cbcColSolution_)) ;
1898                whichGenerator_[numberOld++] = -1;
1899                theseCuts.insert(*thisCut) ;
1900            }
1901        }
1902    }
1903    delete [] eachCuts;
1904    return status;
1905}
1906/*
1907  Locks a thread if parallel so that stuff like cut pool
1908  can be updated and/or used.
1909*/
1910void
1911CbcModel::lockThread()
1912{
1913    if (masterThread_ && (threadMode_&1) == 0)
1914        masterThread_->lockThread();
1915}
1916/*
1917  Unlocks a thread if parallel
1918*/
1919void
1920CbcModel::unlockThread()
1921{
1922    if (masterThread_ && (threadMode_&1) == 0)
1923        masterThread_->unlockThread();
1924}
1925// Returns true if locked
1926bool
1927CbcModel::isLocked() const
1928{
1929    if (masterThread_) {
1930        return (masterThread_->locked());
1931    } else {
1932        return true;
1933    }
1934}
1935// Stop a child
1936void
1937CbcModel::setInfoInChild(int type, CbcThread * info)
1938{
1939    if (type == -3) {
1940        // set up
1941        masterThread_ = info;
1942    } else if (type == -2) {
1943        numberThreads_ = 0; // signal to stop
1944    } else {
1945        // make sure message handler will be deleted
1946        defaultHandler_ = true;
1947        ownObjects_ = false;
1948        delete solverCharacteristics_;
1949        solverCharacteristics_ = NULL;
1950        if (type >= 0) {
1951            delete [] object_; // may be able to when all over to CbcThread
1952            for (int i = 0; i < numberCutGenerators_; i++) {
1953                delete generator_[i];
1954                generator_[i] = NULL;
1955                //delete virginGenerator_[i];
1956                //virginGenerator_[i]=NULL;
1957            }
1958            //generator_[0] = NULL;
1959            //delete [] generator_;
1960            //generator_ = NULL;
1961            numberCutGenerators_ = 0;
1962        } else {
1963            for (int i = 0; i < numberCutGenerators_; i++) {
1964                generator_[i] = NULL;
1965            }
1966        }
1967        object_ = NULL;
1968    }
1969}
1970
1971/// Indicates whether Cbc library has been compiled with multithreading support
1972bool CbcModel::haveMultiThreadSupport() { return true; }
1973
1974#else
1975// Default constructor
1976CbcBaseModel::CbcBaseModel() {}
1977
1978bool CbcModel::haveMultiThreadSupport() { return false; }
1979#endif
1980
Note: See TracBrowser for help on using the repository browser.