Scippy

    SCIP

    Solving Constraint Integer Programs

    tpi_openmp.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file tpi_openmp.c
    26 * @ingroup TASKINTERFACE
    27 * @brief the interface functions for openmp
    28 * @author Stephen J. Maher
    29 * @author Leona Gottwald
    30 * @author Marc Pfetsch
    31 */
    32
    33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    34
    35#include "tpi/tpi.h"
    37#include "scip/pub_message.h"
    38#include "scip/pub_misc.h"
    39#include <omp.h>
    40
    41/* macros for direct access */
    42
    43/* lock */
    44#define SCIPompInitLock(lock) (omp_init_lock(lock), SCIP_OKAY)
    45#define SCIPompDestroyLock(lock) (omp_destroy_lock(lock))
    46#define SCIPompAcquireLock(lock) (omp_set_lock(lock), SCIP_OKAY)
    47#define SCIPompReleaseLock(lock) (omp_unset_lock(lock), SCIP_OKAY)
    48
    49/* condition */
    50#define SCIPompInitCondition(condition) ( omp_init_lock(&(condition)->_lock), \
    51 (condition)->_waiters = 0, (condition)->_waitnum = 0, (condition)->_signals = 0, SCIP_OKAY )
    52#define SCIPompDestroyCondition(condition) do { assert((condition)->_waiters == 0); assert((condition)->_waitnum == 0); assert((condition)->_signals == 0); omp_destroy_lock(&(condition)->_lock); } while(0)
    53
    54
    55/** struct containing lock */
    57{
    58 omp_lock_t lock;
    59};
    60
    61/** struct for condition */
    63{
    64 omp_lock_t _lock;
    65 int _waiters;
    66 int _waitnum;
    67 int _signals;
    68};
    69
    70
    71/** A job added to the queue */
    73{
    74 int jobid; /**< id to identify jobs from a common process */
    75 struct SCIP_Job* nextjob; /**< pointer to the next job in the queue */
    76 SCIP_RETCODE (*jobfunc)(void* args);/**< pointer to the job function */
    77 void* args; /**< pointer to the function arguments */
    78 SCIP_RETCODE retcode; /**< return code of the job */
    79};
    80
    81/** the thread pool job queue */
    83{
    84 SCIP_JOB* firstjob; /**< pointer to the first job in the queue */
    85 SCIP_JOB* lastjob; /**< pointer to the last job in the queue */
    86 int njobs; /**< number of jobs in the queue */
    87};
    89
    91{
    92 SCIP_JOBQUEUE jobqueue; /**< queue of unprocessed jobs */
    93 SCIP_JOB** currentjobs; /**< array with slot for each thread to store the currently running job */
    94 int ncurrentjobs; /**< number of currently running jobs */
    95 int nthreads; /**< number of threads */
    96 SCIP_JOBQUEUE finishedjobs; /**< jobqueue containing the finished jobs */
    97 omp_lock_t lock; /**< lock to protect this stucture from concurrent access */
    98 SCIP_CONDITION jobfinished; /**< condition to signal if a job was finished */
    99};
    101
    102static SCIP_JOBQUEUES* _jobqueues = NULL;
    103
    104
    105/** create job queue */
    106static
    108 int nthreads, /**< the number of threads */
    109 int qsize, /**< the queue size */
    110 SCIP_Bool blockwhenfull /**< should the queue be blocked from new jobs when full */
    111 )
    112{
    113 int i;
    114
    115 assert(nthreads >= 0);
    116 assert(qsize >= 0);
    117 SCIP_UNUSED( blockwhenfull );
    118
    119 /* allocting memory for the job queue */
    120 SCIP_ALLOC( BMSallocMemory(&_jobqueues) );
    121 _jobqueues->jobqueue.firstjob = NULL;
    122 _jobqueues->jobqueue.lastjob = NULL;
    123 _jobqueues->jobqueue.njobs = 0;
    124 _jobqueues->finishedjobs.firstjob = NULL;
    125 _jobqueues->finishedjobs.lastjob = NULL;
    126 _jobqueues->finishedjobs.njobs = 0;
    127 _jobqueues->ncurrentjobs = 0;
    128
    129 _jobqueues->nthreads = nthreads;
    131
    132 for( i = 0; i < nthreads; ++i )
    133 _jobqueues->currentjobs[i] = NULL;
    134
    135 SCIP_CALL( SCIPompInitLock(&_jobqueues->lock) );
    137
    138 return SCIP_OKAY;
    139}
    140
    141
    142/** free job queue */
    143static
    145 void
    146 )
    147{
    148 assert(_jobqueues != NULL);
    149
    150 SCIPompDestroyLock(&_jobqueues->lock);
    152 BMSfreeMemoryArray(&_jobqueues->currentjobs);
    153
    154 BMSfreeMemory(&_jobqueues);
    155
    156 return SCIP_OKAY;
    157}
    158
    159
    160/** execute job */
    161static
    163 SCIP_JOB* job /**< the job to be executed in parallel */
    164 )
    165{
    166 int threadnum;
    167
    168 threadnum = SCIPtpiGetThreadNum();
    169
    170 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
    171 _jobqueues->currentjobs[threadnum] = job;
    172 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
    173
    174 job->retcode = (*(job->jobfunc))(job->args);
    175
    176 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
    177 _jobqueues->ncurrentjobs--;
    178 _jobqueues->currentjobs[threadnum] = NULL;
    179
    180 /* insert job into finished jobs */
    181 if( _jobqueues->finishedjobs.njobs == 0 )
    182 {
    183 _jobqueues->finishedjobs.firstjob = job;
    184 _jobqueues->finishedjobs.lastjob = job;
    185 }
    186 else
    187 {
    188 _jobqueues->finishedjobs.lastjob->nextjob = job;
    189 _jobqueues->finishedjobs.lastjob = job;
    190 }
    191
    192 ++_jobqueues->finishedjobs.njobs;
    193
    195
    196 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
    197}
    198
    199/** wait for a condition */
    201 SCIP_CONDITION* condition, /**< condition to wait for */
    202 SCIP_LOCK* lock /**< corresponding lock */
    203 )
    204{
    205 int waitnum;
    206
    207 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    208 waitnum = ++condition->_waitnum;
    209
    210 ++condition->_waiters;
    211
    213
    214 do
    215 {
    216 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    217 #pragma omp taskyield
    218 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    219 }
    220 while( condition->_signals < waitnum );
    221
    222 --condition->_waiters;
    223
    224 if( condition->_waiters == 0 )
    225 {
    226 condition->_signals = 0;
    227 condition->_waitnum = 0;
    228 }
    229
    230 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    231
    233
    234 return SCIP_OKAY;
    235}
    236
    237/** wait for a condition (direct access to lock) */
    238static
    240 SCIP_CONDITION* condition, /**< condition to wait for */
    241 omp_lock_t* lock /**< corresponding lock */
    242 )
    243{
    244 int waitnum;
    245
    246 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    247 waitnum = ++condition->_waitnum;
    248
    249 ++condition->_waiters;
    250
    252
    253 do
    254 {
    255 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    256 #pragma omp taskyield
    257 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    258 }
    259 while( condition->_signals < waitnum );
    260
    261 --condition->_waiters;
    262
    263 if( condition->_waiters == 0 )
    264 {
    265 condition->_signals = 0;
    266 condition->_waitnum = 0;
    267 }
    268
    269 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    270
    272
    273 return SCIP_OKAY;
    274}
    275
    276
    277/** process jobs from job queue
    278 *
    279 * The job will only be added when the number of active jobs is equal to the number of threads.
    280 * As such, there will always be number of threads + 1 tasks available for the scheduler to run.
    281 */
    282static
    284 void
    285 )
    286{
    287 SCIP_JOB* job;
    288
    289 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
    290
    291 while( _jobqueues->ncurrentjobs == SCIPtpiGetNumThreads() )
    292 {
    293 SCIP_CALL_ABORT( SCIPompWaitCondition(&_jobqueues->jobfinished, &_jobqueues->lock) );
    294 }
    295
    296 if( _jobqueues->jobqueue.njobs == 1 )
    297 {
    298 job = _jobqueues->jobqueue.firstjob;
    299 _jobqueues->jobqueue.firstjob = NULL;
    300 _jobqueues->jobqueue.lastjob = NULL;
    301 --(_jobqueues->jobqueue.njobs);
    302 }
    303 else if( _jobqueues->jobqueue.njobs > 1 )
    304 {
    305 job = _jobqueues->jobqueue.firstjob;
    306 _jobqueues->jobqueue.firstjob = job->nextjob;
    307 --_jobqueues->jobqueue.njobs;
    308 }
    309 else
    310 {
    311 job = NULL;
    312 }
    313
    314 ++(_jobqueues->ncurrentjobs);
    315 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
    316
    317 if( job )
    318 {
    319 executeJob(job);
    320 }
    321}
    322
    323
    324/** adding a job to the job queue
    325 *
    326 * This gives some more flexibility in the handling of new jobs.
    327 * IMPORTANT: This function MUST be called from within a mutex.
    328 */
    329static
    331 SCIP_JOB* newjob
    332 )
    333{
    334 /* @todo we want to work out what to do with a full job queue. Is there a problem if the limit is hit? */
    335 /* @note it is important to have a queuesize. This will stop the code submitting infinitely many jobs. */
    336 assert(newjob != NULL);
    337
    338 newjob->nextjob = NULL;
    339
    340 /* This function queries the current job list. This could change by other threads writing to the list. So a lock is
    341 * required to ensure that the current joblist remains static. */
    342 SCIP_CALL( SCIPompAcquireLock(&_jobqueues->lock) );
    343
    344 /* checking the status of the job queue */
    345 if( _jobqueues->ncurrentjobs == SCIPtpiGetNumThreads() )
    346 {
    347 if( _jobqueues->jobqueue.njobs == 0 )
    348 {
    349 _jobqueues->jobqueue.firstjob = newjob;
    350 _jobqueues->jobqueue.lastjob = newjob;
    351 }
    352 else /* it is assumed that the jobqueue is not full */
    353 {
    354 _jobqueues->jobqueue.lastjob->nextjob = newjob;
    355 _jobqueues->jobqueue.lastjob = newjob;
    356 }
    357
    358 _jobqueues->jobqueue.njobs++;
    359
    360 SCIP_CALL( SCIPompReleaseLock(&_jobqueues->lock) );
    361
    362 #pragma omp task
    364 }
    365 else
    366 {
    367 assert(_jobqueues->ncurrentjobs < SCIPtpiGetNumThreads());
    368
    369 _jobqueues->ncurrentjobs++;
    370
    371 SCIP_CALL( SCIPompReleaseLock(&_jobqueues->lock) );
    372 /* running the new job */
    373 #pragma omp task firstprivate(newjob)
    374 executeJob(newjob);
    375 }
    376
    377 return SCIP_OKAY;
    378}
    379
    380
    381/** signal a condition */
    383 SCIP_CONDITION* condition /**< condition to signal */
    384 )
    385{
    386 assert( condition != NULL );
    387
    388 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    389
    390 if( condition->_waitnum > condition->_signals )
    391 ++condition->_signals;
    392
    393 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    394
    395 return SCIP_OKAY;
    396}
    397
    398
    399/** broadcase a condition */
    401 SCIP_CONDITION* condition /**< broadcast a condition */
    402 )
    403{
    404 assert( condition != NULL );
    405
    406 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
    407 condition->_signals = condition->_waitnum;
    408 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
    409
    410 return SCIP_OKAY;
    411}
    412
    413
    414
    415/** returns the number of threads */
    417 )
    418{
    419 return omp_get_num_threads();
    420}
    421
    422/** returns the thread number */
    424 )
    425{
    426 return omp_get_thread_num();
    427}
    428
    429/** creates a job for parallel processing */
    431 SCIP_JOB** job, /**< pointer to the job that will be created */
    432 int jobid, /**< the id for the current job */
    433 SCIP_RETCODE (*jobfunc)(void* args),/**< pointer to the job function */
    434 void* jobarg /**< the job's argument */
    435 )
    436{
    438
    439 (*job)->jobid = jobid;
    440 (*job)->jobfunc = jobfunc;
    441 (*job)->args = jobarg;
    442 (*job)->nextjob = NULL;
    443
    444 return SCIP_OKAY;
    445}
    446
    447/** get a new job id for the new set of submitted jobs */
    449 void
    450 )
    451{
    452 static int currentjobid = 0;
    453 int jobid;
    454
    455 #pragma omp atomic capture
    456 jobid = ++currentjobid;
    457
    458 return jobid;
    459}
    460
    461/** submit a job for parallel processing; the return value is a globally defined status */
    463 SCIP_JOB* job, /**< pointer to the job to be submitted */
    464 SCIP_SUBMITSTATUS* status /**< pointer to store the submit status */
    465 )
    466{
    467 assert(_jobqueues != NULL);
    468
    469 *status = SCIP_SUBMIT_SUCCESS;
    471
    472 return SCIP_OKAY;
    473}
    474
    475
    476/** check whether a job is running */
    477static
    479 int jobid /**< job id to check */
    480 )
    481{
    482 int i;
    483
    484 if( _jobqueues->ncurrentjobs > 0 )
    485 {
    486 for( i = 0; i < _jobqueues->nthreads; ++i )
    487 {
    488 if( _jobqueues->currentjobs[i] != NULL && _jobqueues->currentjobs[i]->jobid == jobid )
    489 return TRUE;
    490 }
    491 }
    492
    493 return FALSE;
    494}
    495
    496
    497/** check whether a job is waiting */
    498static
    500 int jobid /**< job id to check */
    501 )
    502{
    503 if( _jobqueues->jobqueue.njobs > 0 )
    504 {
    505 SCIP_JOB* currjob;
    506 currjob = _jobqueues->jobqueue.firstjob;
    507
    508 do
    509 {
    510 if( currjob->jobid == jobid )
    511 return TRUE;
    512
    513 if( currjob == _jobqueues->jobqueue.lastjob )
    514 break;
    515
    516 currjob = currjob->nextjob;
    517 }
    518 while( TRUE ); /*lint !e506*/
    519 }
    520
    521 return FALSE;
    522}
    523
    524
    525/** blocks until all jobs of the given jobid have finished
    526 * and then returns the smallest SCIP_RETCODE of all the jobs */
    528 int jobid /**< the jobid of the jobs to wait for */
    529 )
    530{
    531 SCIP_RETCODE retcode;
    532
    533 retcode = SCIP_OKAY;
    534 SCIP_CALL( SCIPompAcquireLock(&_jobqueues->lock) );
    535
    536 while( isJobRunning(jobid) || isJobWaiting(jobid) )
    537 {
    538 SCIP_CALL( SCIPompWaitCondition(&_jobqueues->jobfinished, &_jobqueues->lock) );
    539 }
    540
    541 if( _jobqueues->finishedjobs.njobs > 0 )
    542 {
    543 SCIP_JOB* currjob = _jobqueues->finishedjobs.firstjob;
    544 SCIP_JOB* prevjob = NULL;
    545
    546 /* finding the location of the processed job in the currentjobs queue */
    547 do
    548 {
    549 if( currjob->jobid == jobid )
    550 {
    551 SCIP_JOB* nextjob;
    552
    553 /* if the job has the right jobid collect its retcode, remove it from the finished job list, and free it */
    554 retcode = MIN(retcode, currjob->retcode);
    555
    556 /* removing the finished job from finished jobs list */
    557 if( currjob == _jobqueues->finishedjobs.firstjob )
    558 _jobqueues->finishedjobs.firstjob = currjob->nextjob;
    559 else
    560 {
    561 if( prevjob != NULL )
    562 prevjob->nextjob = currjob->nextjob; /*lint !e613*/
    563 }
    564
    565 if( currjob == _jobqueues->finishedjobs.lastjob )
    566 _jobqueues->finishedjobs.lastjob = prevjob;
    567
    568 _jobqueues->finishedjobs.njobs--;
    569
    570 /* update currjob and free finished job; prevjob stays the same */
    571 nextjob = currjob->nextjob;
    572 BMSfreeMemory(&currjob);
    573 currjob = nextjob;
    574 }
    575 else
    576 {
    577 prevjob = currjob;
    578 currjob = prevjob->nextjob;
    579 }
    580 }
    581 while( prevjob != _jobqueues->finishedjobs.lastjob );
    582 }
    583 else
    584 {
    585 /* given jobid was not submitted */
    586 printf("err1");
    587 retcode = SCIP_ERROR;
    588 }
    589
    590 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
    591
    592 return retcode;
    593}
    594
    595/** initializes tpi */
    597 int nthreads, /**< the number of threads to be used */
    598 int queuesize, /**< the size of the queue */
    599 SCIP_Bool blockwhenfull /**< should the queue block when full */
    600 )
    601{
    602 omp_set_num_threads(nthreads);
    603 assert(_jobqueues == NULL);
    604
    605 SCIP_CALL( createJobQueue(nthreads, queuesize, blockwhenfull) );
    606
    607 return SCIP_OKAY;
    608}
    609
    610/** deinitializes tpi */
    612 void
    613 )
    614{
    615 assert(_jobqueues != NULL);
    616 assert(_jobqueues->finishedjobs.njobs == 0);
    617 assert(_jobqueues->jobqueue.njobs == 0);
    618 assert(_jobqueues->ncurrentjobs == 0);
    619
    621
    622 return SCIP_OKAY;
    623}
    624
    625
    626/*
    627 * locks
    628 */
    629
    630/** initializes the given lock */
    632 SCIP_LOCK** lock /**< the lock */
    633 )
    634{
    635 assert(lock != NULL);
    636
    638 omp_init_lock(&(*lock)->lock);
    639 return SCIP_OKAY;
    640}
    641
    642/** destroys the given lock */
    644 SCIP_LOCK** lock /**< the lock */
    645 )
    646{
    647 assert(lock != NULL);
    648
    649 omp_destroy_lock(&(*lock)->lock);
    651}
    652
    653/** acquires the given lock */
    655 SCIP_LOCK* lock /**< the lock */
    656 )
    657{
    658 omp_set_lock(&lock->lock);
    659 return SCIP_OKAY;
    660}
    661
    662/** releases the given lock */
    664 SCIP_LOCK* lock /**< the lock */
    665 )
    666{
    667 omp_unset_lock(&lock->lock);
    668 return SCIP_OKAY;
    669}
    670
    671
    672/*
    673 * conditions
    674 */
    675
    676/** initializes the given condition variable */
    678 SCIP_CONDITION** condition /**< condition to be created and initialized */
    679 )
    680{
    681 assert(condition != NULL);
    682
    683 SCIP_ALLOC( BMSallocMemory(condition) );
    684
    685 omp_init_lock(&(*condition)->_lock);
    686 (*condition)->_waiters = 0;
    687 (*condition)->_waitnum = 0;
    688 (*condition)->_signals = 0;
    689
    690 return SCIP_OKAY;
    691}
    692
    693/** destroys the given condition variable */
    695 SCIP_CONDITION** condition /**< condition to be destroyed and freed */
    696 )
    697{
    698 assert((*condition)->_waiters == 0);
    699 assert((*condition)->_waitnum == 0);
    700 assert((*condition)->_signals == 0);
    701
    702 omp_destroy_lock(&(*condition)->_lock);
    703
    704 BMSfreeMemory(condition);
    705}
    706
    707/** indicate whether a working TPI is available */
    709{
    710 return TRUE;
    711}
    712
    713/** get name of library that the TPI interfaces to */
    715 char* name, /**< buffer to store name */
    716 int namesize /**< length of name buffer */
    717 )
    718{
    719 assert(name != NULL);
    720
    721 (void) SCIPsnprintf(name, namesize, "OpenMP %d", _OPENMP); /*lint !e40*/
    722}
    723
    724/** get description of library that the TPI interfaces to */
    726 char* desc, /**< buffer to store description */
    727 int descsize /**< length of description */
    728 )
    729{
    730 assert(desc != NULL);
    731
    732 (void) SCIPsnprintf(desc, descsize, "shared-memory multiprocessing library (openmp.org)");
    733}
    #define NULL
    Definition: def.h:248
    #define SCIP_UNUSED(x)
    Definition: def.h:409
    #define SCIP_Bool
    Definition: def.h:91
    #define MIN(x, y)
    Definition: def.h:224
    #define SCIP_ALLOC(x)
    Definition: def.h:366
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_CALL(x)
    Definition: def.h:355
    int SCIPsnprintf(char *t, int len, const char *s,...)
    Definition: misc.c:10827
    memory allocation routines
    #define BMSfreeMemory(ptr)
    Definition: memory.h:145
    #define BMSallocMemoryArray(ptr, num)
    Definition: memory.h:123
    #define BMSfreeMemoryArray(ptr)
    Definition: memory.h:147
    #define BMSallocMemory(ptr)
    Definition: memory.h:118
    public methods for message output
    public data structures and miscellaneous methods
    SCIP_JOB * lastjob
    Definition: tpi_openmp.c:85
    SCIP_JOB * firstjob
    Definition: tpi_openmp.c:84
    SCIP_JOB ** currentjobs
    Definition: tpi_openmp.c:93
    SCIP_JOBQUEUE finishedjobs
    Definition: tpi_openmp.c:96
    SCIP_JOBQUEUE jobqueue
    Definition: tpi_openmp.c:92
    SCIP_CONDITION jobfinished
    Definition: tpi_openmp.c:98
    omp_lock_t lock
    Definition: tpi_openmp.c:97
    SCIP_RETCODE retcode
    Definition: tpi_openmp.c:78
    struct SCIP_Job * nextjob
    Definition: tpi_openmp.c:75
    void * args
    Definition: tpi_openmp.c:77
    SCIP_RETCODE(* jobfunc)(void *args)
    Definition: tpi_openmp.c:76
    int jobid
    Definition: tpi_openmp.c:74
    omp_lock_t lock
    Definition: tpi_openmp.c:58
    the type definitions for the SCIP parallel interface
    #define SCIPompInitLock(lock)
    Definition: tpi_openmp.c:44
    SCIP_Bool SCIPtpiIsAvailable(void)
    Definition: tpi_openmp.c:708
    #define SCIPompAcquireLock(lock)
    Definition: tpi_openmp.c:46
    SCIP_RETCODE SCIPtpiWaitCondition(SCIP_CONDITION *condition, SCIP_LOCK *lock)
    Definition: tpi_openmp.c:200
    SCIP_RETCODE SCIPtpiCreateJob(SCIP_JOB **job, int jobid, SCIP_RETCODE(*jobfunc)(void *args), void *jobarg)
    Definition: tpi_openmp.c:430
    SCIP_RETCODE SCIPtpiSignalCondition(SCIP_CONDITION *condition)
    Definition: tpi_openmp.c:382
    static SCIP_RETCODE jobQueueAddJob(SCIP_JOB *newjob)
    Definition: tpi_openmp.c:330
    SCIP_RETCODE SCIPtpiAcquireLock(SCIP_LOCK *lock)
    Definition: tpi_openmp.c:654
    #define SCIPompReleaseLock(lock)
    Definition: tpi_openmp.c:47
    #define SCIPompDestroyLock(lock)
    Definition: tpi_openmp.c:45
    int SCIPtpiGetNumThreads()
    Definition: tpi_openmp.c:416
    SCIP_RETCODE SCIPtpiExit(void)
    Definition: tpi_openmp.c:611
    static void executeJob(SCIP_JOB *job)
    Definition: tpi_openmp.c:162
    SCIP_RETCODE SCIPtpiBroadcastCondition(SCIP_CONDITION *condition)
    Definition: tpi_openmp.c:400
    static SCIP_RETCODE freeJobQueue(void)
    Definition: tpi_openmp.c:144
    static void jobQueueProcessJob(void)
    Definition: tpi_openmp.c:283
    SCIP_RETCODE SCIPtpiSubmitJob(SCIP_JOB *job, SCIP_SUBMITSTATUS *status)
    Definition: tpi_openmp.c:462
    void SCIPtpiDestroyLock(SCIP_LOCK **lock)
    Definition: tpi_openmp.c:643
    void SCIPtpiGetLibraryDesc(char *desc, int descsize)
    Definition: tpi_openmp.c:725
    SCIP_RETCODE SCIPtpiCollectJobs(int jobid)
    Definition: tpi_openmp.c:527
    static SCIP_RETCODE SCIPompWaitCondition(SCIP_CONDITION *condition, omp_lock_t *lock)
    Definition: tpi_openmp.c:239
    static SCIP_RETCODE createJobQueue(int nthreads, int qsize, SCIP_Bool blockwhenfull)
    Definition: tpi_openmp.c:107
    static SCIP_Bool isJobRunning(int jobid)
    Definition: tpi_openmp.c:478
    static SCIP_Bool isJobWaiting(int jobid)
    Definition: tpi_openmp.c:499
    void SCIPtpiDestroyCondition(SCIP_CONDITION **condition)
    Definition: tpi_openmp.c:694
    #define SCIPompDestroyCondition(condition)
    Definition: tpi_openmp.c:52
    int SCIPtpiGetNewJobID(void)
    Definition: tpi_openmp.c:448
    void SCIPtpiGetLibraryName(char *name, int namesize)
    Definition: tpi_openmp.c:714
    SCIP_RETCODE SCIPtpiInitLock(SCIP_LOCK **lock)
    Definition: tpi_openmp.c:631
    int SCIPtpiGetThreadNum()
    Definition: tpi_openmp.c:423
    SCIP_RETCODE SCIPtpiReleaseLock(SCIP_LOCK *lock)
    Definition: tpi_openmp.c:663
    SCIP_RETCODE SCIPtpiInitCondition(SCIP_CONDITION **condition)
    Definition: tpi_openmp.c:677
    SCIP_RETCODE SCIPtpiInit(int nthreads, int queuesize, SCIP_Bool blockwhenfull)
    Definition: tpi_openmp.c:596
    #define SCIPompInitCondition(condition)
    Definition: tpi_openmp.c:50
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    @ SCIP_ERROR
    Definition: type_retcode.h:43
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    enum SCIP_Submitstatus SCIP_SUBMITSTATUS
    Definition: type_tpi.h:50
    @ SCIP_SUBMIT_SUCCESS
    Definition: type_tpi.h:48