/** Destructor. */ ~Worker() { if ( handle ) { handle.kill(); handle.join(); } if ( cplex.getImpl() ) { cplex.userfunction(USERACTION_REMOVECALLBACK, 0, NULL, 0, 0, NULL); cplex.end(); } rng.end(); x.end(); obj.end(); model.end(); }
/** Create a new worker. * The constructor mainly does the following: * - create an IloCplex instance that refers to a remote worker, * - load the model in <code>modelfile</code>, * - setup parameters depending on this worker's index, * - start an asynchronous solve. * If anything fails then an exception will be thrown. * @param env The environment used for instantiating Ilo* objects. * @param i The index of the worker to be created. This also * determines the parameter settings to use in this worker. * @param s A pointer to the global solve state. * @param transport The transport name for the IloCplex constructor. * @param argc The argument count for the IloCplex constructor. * @param argv The array of transport arguments for the IloCplex * constructor. * @param modelfile Name of the model to be loaded into the worker. * @param output The output mode. * @param objdiff The minimal difference between so that two * consecutive objective function values are considered * different. */ Worker(IloEnv env, int i, SolveState *s, char const *transport, int argc, char const **argv, char const *modelfile, OUTPUT output, double objdiff) : idx(i), state(s), model(env), cplex(0), handle(0), primal(IloInfinity), dual(-IloInfinity), obj(env), x(env), rng(env), infoHandler(this), outb(idx), outs(&outb) { try { // Create remote object, setup output and load the model. cplex = IloCplex(model, transport, argc, argv); switch (output) { case OUTPUT_SILENT: // Disable output on the output and warning stream. cplex.setOut(env.getNullStream()); cplex.setWarning(env.getNullStream()); break; case OUTPUT_PREFIXED: // Redirect output to our custom stream. cplex.setOut(outs); cplex.setWarning(outs); break; case OUTPUT_LOG: // Nothing to do here. By default output is enabled. break; } cplex.importModel(model, modelfile, obj, x, rng); if ( obj.getSense() == IloObjective::Minimize ) { primal = -IloInfinity; dual = IloInfinity; } // We set the thread count for each solver to 1 so that we do not // run into problems if multiple solves are performed on the same // machine. cplex.setParam(IloCplex::Param::Threads, 1); // Each worker runs with a different random seed. This way we // get different paths through the tree even if the other // parameter settings are the same. cplex.setParam(IloCplex::Param::RandomSeed, idx); // Apply parameter settings. for (class ParamValue const *vals = settings[idx % NUMSETTINGS].values; vals->isValid(); ++vals) vals->apply(cplex); // Install callback and set objective change. int status = cplex.userfunction (USERACTION_ADDCALLBACK, 0, NULL, 0, 0, NULL); if ( status ) throw status; IloCplex::Serializer s; s.add(objdiff); status = cplex.userfunction (USERACTION_CHANGEOBJDIFF, s.getRawLength(), s.getRawData(), 0, 0, NULL); if ( status ) throw status; // Register the handler that will process info messages sent // from the worker. cplex.setRemoteInfoHandler(&infoHandler); // Everything is setup. Launch the asynchronous solve. handle = cplex.solve(true); } catch (...) { // In case of an exception we need to take some special // cleanup actions. Note that if we get here then the // solve cannot have been started and we don't need to // kill or join the asynchronous solve. if ( cplex.getImpl() ) cplex.end(); rng.end(); x.end(); obj.end(); model.end(); throw; } }