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-2024 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 <omp.h>
39
40/* macros for direct access */
41
42/* lock */
43#define SCIPompInitLock(lock) (omp_init_lock(lock), SCIP_OKAY)
44#define SCIPompDestroyLock(lock) (omp_destroy_lock(lock))
45#define SCIPompAcquireLock(lock) (omp_set_lock(lock), SCIP_OKAY)
46#define SCIPompReleaseLock(lock) (omp_unset_lock(lock), SCIP_OKAY)
47
48/* condition */
49#define SCIPompInitCondition(condition) ( omp_init_lock(&(condition)->_lock), \
50 (condition)->_waiters = 0, (condition)->_waitnum = 0, (condition)->_signals = 0, SCIP_OKAY )
51#define SCIPompDestroyCondition(condition) do { assert((condition)->_waiters == 0); assert((condition)->_waitnum == 0); assert((condition)->_signals == 0); omp_destroy_lock(&(condition)->_lock); } while(0)
52
53
54/** struct containing lock */
56{
57 omp_lock_t lock;
58};
59
60/** struct for condition */
62{
63 omp_lock_t _lock;
64 int _waiters;
65 int _waitnum;
66 int _signals;
67};
68
69
70/** A job added to the queue */
72{
73 int jobid; /**< id to identify jobs from a common process */
74 struct SCIP_Job* nextjob; /**< pointer to the next job in the queue */
75 SCIP_RETCODE (*jobfunc)(void* args);/**< pointer to the job function */
76 void* args; /**< pointer to the function arguments */
77 SCIP_RETCODE retcode; /**< return code of the job */
78};
79
80/** the thread pool job queue */
82{
83 SCIP_JOB* firstjob; /**< pointer to the first job in the queue */
84 SCIP_JOB* lastjob; /**< pointer to the last job in the queue */
85 int njobs; /**< number of jobs in the queue */
86};
88
90{
91 SCIP_JOBQUEUE jobqueue; /**< queue of unprocessed jobs */
92 SCIP_JOB** currentjobs; /**< array with slot for each thread to store the currently running job */
93 int ncurrentjobs; /**< number of currently running jobs */
94 int nthreads; /**< number of threads */
95 SCIP_JOBQUEUE finishedjobs; /**< jobqueue containing the finished jobs */
96 omp_lock_t lock; /**< lock to protect this stucture from concurrent access */
97 SCIP_CONDITION jobfinished; /**< condition to signal if a job was finished */
98};
100
101static SCIP_JOBQUEUES* _jobqueues = NULL;
102
103
104/** create job queue */
105static
107 int nthreads, /**< the number of threads */
108 int qsize, /**< the queue size */
109 SCIP_Bool blockwhenfull /**< should the queue be blocked from new jobs when full */
110 )
111{
112 int i;
113
114 assert(nthreads >= 0);
115 assert(qsize >= 0);
116 SCIP_UNUSED( blockwhenfull );
117
118 /* allocting memory for the job queue */
119 SCIP_ALLOC( BMSallocMemory(&_jobqueues) );
120 _jobqueues->jobqueue.firstjob = NULL;
121 _jobqueues->jobqueue.lastjob = NULL;
122 _jobqueues->jobqueue.njobs = 0;
123 _jobqueues->finishedjobs.firstjob = NULL;
124 _jobqueues->finishedjobs.lastjob = NULL;
125 _jobqueues->finishedjobs.njobs = 0;
126 _jobqueues->ncurrentjobs = 0;
127
128 _jobqueues->nthreads = nthreads;
130
131 for( i = 0; i < nthreads; ++i )
132 _jobqueues->currentjobs[i] = NULL;
133
134 SCIP_CALL( SCIPompInitLock(&_jobqueues->lock) );
136
137 return SCIP_OKAY;
138}
139
140
141/** free job queue */
142static
144 void
145 )
146{
147 assert(_jobqueues != NULL);
148
149 SCIPompDestroyLock(&_jobqueues->lock);
151 BMSfreeMemoryArray(&_jobqueues->currentjobs);
152
153 BMSfreeMemory(&_jobqueues);
154
155 return SCIP_OKAY;
156}
157
158
159/** execute job */
160static
162 SCIP_JOB* job /**< the job to be executed in parallel */
163 )
164{
165 int threadnum;
166
167 threadnum = SCIPtpiGetThreadNum();
168
169 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
170 _jobqueues->currentjobs[threadnum] = job;
171 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
172
173 job->retcode = (*(job->jobfunc))(job->args);
174
175 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
176 _jobqueues->ncurrentjobs--;
177 _jobqueues->currentjobs[threadnum] = NULL;
178
179 /* insert job into finished jobs */
180 if( _jobqueues->finishedjobs.njobs == 0 )
181 {
182 _jobqueues->finishedjobs.firstjob = job;
183 _jobqueues->finishedjobs.lastjob = job;
184 }
185 else
186 {
187 _jobqueues->finishedjobs.lastjob->nextjob = job;
188 _jobqueues->finishedjobs.lastjob = job;
189 }
190
191 ++_jobqueues->finishedjobs.njobs;
192
194
195 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
196}
197
198/** wait for a condition */
200 SCIP_CONDITION* condition, /**< condition to wait for */
201 SCIP_LOCK* lock /**< corresponding lock */
202 )
203{
204 int waitnum;
205
207
208 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
209 waitnum = ++condition->_waitnum;
210
211 ++condition->_waiters;
212
213 do
214 {
215 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
216 #pragma omp taskyield
217 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
218 }
219 while( condition->_signals < waitnum );
220
221 --condition->_waiters;
222
223 if( condition->_waiters == 0 )
224 {
225 condition->_signals = 0;
226 condition->_waitnum = 0;
227 }
228
229 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
230
232
233 return SCIP_OKAY;
234}
235
236/** wait for a condition (direct access to lock) */
237static
239 SCIP_CONDITION* condition, /**< condition to wait for */
240 omp_lock_t* lock /**< corresponding lock */
241 )
242{
243 int waitnum;
244
246
247 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
248 waitnum = ++condition->_waitnum;
249
250 ++condition->_waiters;
251
252 do
253 {
254 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
255 #pragma omp taskyield
256 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
257 }
258 while( condition->_signals < waitnum );
259
260 --condition->_waiters;
261
262 if( condition->_waiters == 0 )
263 {
264 condition->_signals = 0;
265 condition->_waitnum = 0;
266 }
267
268 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
269
271
272 return SCIP_OKAY;
273}
274
275
276/** process jobs from job queue
277 *
278 * The job will only be added when the number of active jobs is equal to the number of threads.
279 * As such, there will always be number of threads + 1 tasks available for the scheduler to run.
280 */
281static
283 void
284 )
285{
286 SCIP_JOB* job;
287
288 SCIP_CALL_ABORT( SCIPompAcquireLock(&_jobqueues->lock) );
289
290 while( _jobqueues->ncurrentjobs == SCIPtpiGetNumThreads() )
291 {
292 SCIP_CALL_ABORT( SCIPompWaitCondition(&_jobqueues->jobfinished, &_jobqueues->lock) );
293 }
294
295 if( _jobqueues->jobqueue.njobs == 1 )
296 {
297 job = _jobqueues->jobqueue.firstjob;
298 _jobqueues->jobqueue.firstjob = NULL;
299 _jobqueues->jobqueue.lastjob = NULL;
300 --(_jobqueues->jobqueue.njobs);
301 }
302 else if( _jobqueues->jobqueue.njobs > 1 )
303 {
304 job = _jobqueues->jobqueue.firstjob;
305 _jobqueues->jobqueue.firstjob = job->nextjob;
306 --_jobqueues->jobqueue.njobs;
307 }
308 else
309 {
310 job = NULL;
311 }
312
313 ++(_jobqueues->ncurrentjobs);
314 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
315
316 if( job )
317 {
318 executeJob(job);
319 }
320}
321
322
323/** adding a job to the job queue
324 *
325 * This gives some more flexibility in the handling of new jobs.
326 * IMPORTANT: This function MUST be called from within a mutex.
327 */
328static
330 SCIP_JOB* newjob
331 )
332{
333 /* @todo we want to work out what to do with a full job queue. Is there a problem if the limit is hit? */
334 /* @note it is important to have a queuesize. This will stop the code submitting infinitely many jobs. */
335 assert(newjob != NULL);
336
337 newjob->nextjob = NULL;
338
339 /* This function queries the current job list. This could change by other threads writing to the list. So a lock is
340 * required to ensure that the current joblist remains static. */
341 SCIP_CALL( SCIPompAcquireLock(&_jobqueues->lock) );
342
343 /* checking the status of the job queue */
344 if( _jobqueues->ncurrentjobs == SCIPtpiGetNumThreads() )
345 {
346 if( _jobqueues->jobqueue.njobs == 0 )
347 {
348 _jobqueues->jobqueue.firstjob = newjob;
349 _jobqueues->jobqueue.lastjob = newjob;
350 }
351 else /* it is assumed that the jobqueue is not full */
352 {
353 _jobqueues->jobqueue.lastjob->nextjob = newjob;
354 _jobqueues->jobqueue.lastjob = newjob;
355 }
356
357 _jobqueues->jobqueue.njobs++;
358
359 SCIP_CALL( SCIPompReleaseLock(&_jobqueues->lock) );
360
361 #pragma omp task
363 }
364 else
365 {
366 assert(_jobqueues->ncurrentjobs < SCIPtpiGetNumThreads());
367
368 _jobqueues->ncurrentjobs++;
369
370 SCIP_CALL( SCIPompReleaseLock(&_jobqueues->lock) );
371 /* running the new job */
372 #pragma omp task firstprivate(newjob)
373 executeJob(newjob);
374 }
375
376 return SCIP_OKAY;
377}
378
379
380/** signal a condition */
382 SCIP_CONDITION* condition /**< condition to signal */
383 )
384{
385 assert( condition != NULL );
386
387 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
388
389 if( condition->_waitnum > condition->_signals )
390 ++condition->_signals;
391
392 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
393
394 return SCIP_OKAY;
395}
396
397
398/** broadcase a condition */
400 SCIP_CONDITION* condition /**< broadcast a condition */
401 )
402{
403 assert( condition != NULL );
404
405 SCIP_CALL( SCIPompAcquireLock(&condition->_lock) );
406 condition->_signals = condition->_waitnum;
407 SCIP_CALL( SCIPompReleaseLock(&condition->_lock) );
408
409 return SCIP_OKAY;
410}
411
412
413
414/** returns the number of threads */
416 )
417{
418 return omp_get_num_threads();
419}
420
421/** returns the thread number */
423 )
424{
425 return omp_get_thread_num();
426}
427
428/** creates a job for parallel processing */
430 SCIP_JOB** job, /**< pointer to the job that will be created */
431 int jobid, /**< the id for the current job */
432 SCIP_RETCODE (*jobfunc)(void* args),/**< pointer to the job function */
433 void* jobarg /**< the job's argument */
434 )
435{
437
438 (*job)->jobid = jobid;
439 (*job)->jobfunc = jobfunc;
440 (*job)->args = jobarg;
441 (*job)->nextjob = NULL;
442
443 return SCIP_OKAY;
444}
445
446/** get a new job id for the new set of submitted jobs */
448 void
449 )
450{
451 static int currentjobid = 0;
452 int jobid;
453
454 #pragma omp atomic capture
455 jobid = ++currentjobid;
456
457 return jobid;
458}
459
460/** submit a job for parallel processing; the return value is a globally defined status */
462 SCIP_JOB* job, /**< pointer to the job to be submitted */
463 SCIP_SUBMITSTATUS* status /**< pointer to store the submit status */
464 )
465{
466 assert(_jobqueues != NULL);
467
468 *status = SCIP_SUBMIT_SUCCESS;
470
471 return SCIP_OKAY;
472}
473
474
475/** check whether a job is running */
476static
478 int jobid /**< job id to check */
479 )
480{
481 int i;
482
483 if( _jobqueues->ncurrentjobs > 0 )
484 {
485 for( i = 0; i < _jobqueues->nthreads; ++i )
486 {
487 if( _jobqueues->currentjobs[i] != NULL && _jobqueues->currentjobs[i]->jobid == jobid )
488 return TRUE;
489 }
490 }
491
492 return FALSE;
493}
494
495
496/** check whether a job is waiting */
497static
499 int jobid /**< job id to check */
500 )
501{
502 if( _jobqueues->jobqueue.njobs > 0 )
503 {
504 SCIP_JOB* currjob;
505 currjob = _jobqueues->jobqueue.firstjob;
506
507 do
508 {
509 if( currjob->jobid == jobid )
510 return TRUE;
511
512 if( currjob == _jobqueues->jobqueue.lastjob )
513 break;
514
515 currjob = currjob->nextjob;
516 }
517 while( TRUE ); /*lint !e506*/
518 }
519
520 return FALSE;
521}
522
523
524/** blocks until all jobs of the given jobid have finished
525 * and then returns the smallest SCIP_RETCODE of all the jobs */
527 int jobid /**< the jobid of the jobs to wait for */
528 )
529{
530 SCIP_RETCODE retcode;
531
532 retcode = SCIP_OKAY;
533 SCIP_CALL( SCIPompAcquireLock(&_jobqueues->lock) );
534
535 while( isJobRunning(jobid) || isJobWaiting(jobid) )
536 {
537 SCIP_CALL( SCIPompWaitCondition(&_jobqueues->jobfinished, &_jobqueues->lock) );
538 }
539
540 if( _jobqueues->finishedjobs.njobs > 0 )
541 {
542 SCIP_JOB* currjob = _jobqueues->finishedjobs.firstjob;
543 SCIP_JOB* prevjob = NULL;
544
545 /* finding the location of the processed job in the currentjobs queue */
546 do
547 {
548 if( currjob->jobid == jobid )
549 {
550 SCIP_JOB* nextjob;
551
552 /* if the job has the right jobid collect its retcode, remove it from the finished job list, and free it */
553 retcode = MIN(retcode, currjob->retcode);
554
555 /* removing the finished job from finished jobs list */
556 if( currjob == _jobqueues->finishedjobs.firstjob )
557 _jobqueues->finishedjobs.firstjob = currjob->nextjob;
558 else
559 {
560 if( prevjob != NULL )
561 prevjob->nextjob = currjob->nextjob; /*lint !e613*/
562 }
563
564 if( currjob == _jobqueues->finishedjobs.lastjob )
565 _jobqueues->finishedjobs.lastjob = prevjob;
566
567 _jobqueues->finishedjobs.njobs--;
568
569 /* update currjob and free finished job; prevjob stays the same */
570 nextjob = currjob->nextjob;
571 BMSfreeMemory(&currjob);
572 currjob = nextjob;
573 }
574 else
575 {
576 prevjob = currjob;
577 currjob = prevjob->nextjob;
578 }
579 }
580 while( prevjob != _jobqueues->finishedjobs.lastjob );
581 }
582 else
583 {
584 /* given jobid was not submitted */
585 printf("err1");
586 retcode = SCIP_ERROR;
587 }
588
589 SCIP_CALL_ABORT( SCIPompReleaseLock(&_jobqueues->lock) );
590
591 return retcode;
592}
593
594/** initializes tpi */
596 int nthreads, /**< the number of threads to be used */
597 int queuesize, /**< the size of the queue */
598 SCIP_Bool blockwhenfull /**< should the queue block when full */
599 )
600{
601 omp_set_num_threads(nthreads);
602 assert(_jobqueues == NULL);
603
604 SCIP_CALL( createJobQueue(nthreads, queuesize, blockwhenfull) );
605
606 return SCIP_OKAY;
607}
608
609/** deinitializes tpi */
611 void
612 )
613{
614 assert(_jobqueues != NULL);
615 assert(_jobqueues->finishedjobs.njobs == 0);
616 assert(_jobqueues->jobqueue.njobs == 0);
617 assert(_jobqueues->ncurrentjobs == 0);
618
620
621 return SCIP_OKAY;
622}
623
624
625/*
626 * locks
627 */
628
629/** initializes the given lock */
631 SCIP_LOCK** lock /**< the lock */
632 )
633{
634 assert(lock != NULL);
635
637 omp_init_lock(&(*lock)->lock);
638 return SCIP_OKAY;
639}
640
641/** destroys the given lock */
643 SCIP_LOCK** lock /**< the lock */
644 )
645{
646 assert(lock != NULL);
647
648 omp_destroy_lock(&(*lock)->lock);
650}
651
652/** acquires the given lock */
654 SCIP_LOCK* lock /**< the lock */
655 )
656{
657 omp_set_lock(&lock->lock);
658 return SCIP_OKAY;
659}
660
661/** releases the given lock */
663 SCIP_LOCK* lock /**< the lock */
664 )
665{
666 omp_unset_lock(&lock->lock);
667 return SCIP_OKAY;
668}
669
670
671/*
672 * conditions
673 */
674
675/** initializes the given condition variable */
677 SCIP_CONDITION** condition /**< condition to be created and initialized */
678 )
679{
680 assert(condition != NULL);
681
682 SCIP_ALLOC( BMSallocMemory(condition) );
683
684 omp_init_lock(&(*condition)->_lock);
685 (*condition)->_waiters = 0;
686 (*condition)->_waitnum = 0;
687 (*condition)->_signals = 0;
688
689 return SCIP_OKAY;
690}
691
692/** destroys the given condition variable */
694 SCIP_CONDITION** condition /**< condition to be destroyed and freed */
695 )
696{
697 assert((*condition)->_waiters == 0);
698 assert((*condition)->_waitnum == 0);
699 assert((*condition)->_signals == 0);
700
701 omp_destroy_lock(&(*condition)->_lock);
702
703 BMSfreeMemory(condition);
704}
#define NULL
Definition: def.h:267
#define SCIP_UNUSED(x)
Definition: def.h:428
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define SCIP_ALLOC(x)
Definition: def.h:385
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIP_CALL_ABORT(x)
Definition: def.h:353
#define SCIP_CALL(x)
Definition: def.h:374
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
SCIP_JOB * lastjob
Definition: tpi_openmp.c:84
SCIP_JOB * firstjob
Definition: tpi_openmp.c:83
SCIP_JOB ** currentjobs
Definition: tpi_openmp.c:92
SCIP_JOBQUEUE finishedjobs
Definition: tpi_openmp.c:95
SCIP_JOBQUEUE jobqueue
Definition: tpi_openmp.c:91
SCIP_CONDITION jobfinished
Definition: tpi_openmp.c:97
omp_lock_t lock
Definition: tpi_openmp.c:96
SCIP_RETCODE retcode
Definition: tpi_openmp.c:77
struct SCIP_Job * nextjob
Definition: tpi_openmp.c:74
void * args
Definition: tpi_openmp.c:76
SCIP_RETCODE(* jobfunc)(void *args)
Definition: tpi_openmp.c:75
int jobid
Definition: tpi_openmp.c:73
omp_lock_t lock
Definition: tpi_openmp.c:57
the type definitions for the SCIP parallel interface
#define SCIPompInitLock(lock)
Definition: tpi_openmp.c:43
#define SCIPompAcquireLock(lock)
Definition: tpi_openmp.c:45
SCIP_RETCODE SCIPtpiWaitCondition(SCIP_CONDITION *condition, SCIP_LOCK *lock)
Definition: tpi_openmp.c:199
SCIP_RETCODE SCIPtpiCreateJob(SCIP_JOB **job, int jobid, SCIP_RETCODE(*jobfunc)(void *args), void *jobarg)
Definition: tpi_openmp.c:429
SCIP_RETCODE SCIPtpiSignalCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:381
static SCIP_RETCODE jobQueueAddJob(SCIP_JOB *newjob)
Definition: tpi_openmp.c:329
SCIP_RETCODE SCIPtpiAcquireLock(SCIP_LOCK *lock)
Definition: tpi_openmp.c:653
#define SCIPompReleaseLock(lock)
Definition: tpi_openmp.c:46
#define SCIPompDestroyLock(lock)
Definition: tpi_openmp.c:44
int SCIPtpiGetNumThreads()
Definition: tpi_openmp.c:415
SCIP_RETCODE SCIPtpiExit(void)
Definition: tpi_openmp.c:610
static void executeJob(SCIP_JOB *job)
Definition: tpi_openmp.c:161
SCIP_RETCODE SCIPtpiBroadcastCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:399
static SCIP_RETCODE freeJobQueue(void)
Definition: tpi_openmp.c:143
static void jobQueueProcessJob(void)
Definition: tpi_openmp.c:282
SCIP_RETCODE SCIPtpiSubmitJob(SCIP_JOB *job, SCIP_SUBMITSTATUS *status)
Definition: tpi_openmp.c:461
void SCIPtpiDestroyLock(SCIP_LOCK **lock)
Definition: tpi_openmp.c:642
SCIP_RETCODE SCIPtpiCollectJobs(int jobid)
Definition: tpi_openmp.c:526
static SCIP_RETCODE SCIPompWaitCondition(SCIP_CONDITION *condition, omp_lock_t *lock)
Definition: tpi_openmp.c:238
static SCIP_RETCODE createJobQueue(int nthreads, int qsize, SCIP_Bool blockwhenfull)
Definition: tpi_openmp.c:106
static SCIP_Bool isJobRunning(int jobid)
Definition: tpi_openmp.c:477
static SCIP_Bool isJobWaiting(int jobid)
Definition: tpi_openmp.c:498
void SCIPtpiDestroyCondition(SCIP_CONDITION **condition)
Definition: tpi_openmp.c:693
#define SCIPompDestroyCondition(condition)
Definition: tpi_openmp.c:51
int SCIPtpiGetNewJobID(void)
Definition: tpi_openmp.c:447
SCIP_RETCODE SCIPtpiInitLock(SCIP_LOCK **lock)
Definition: tpi_openmp.c:630
int SCIPtpiGetThreadNum()
Definition: tpi_openmp.c:422
SCIP_RETCODE SCIPtpiReleaseLock(SCIP_LOCK *lock)
Definition: tpi_openmp.c:662
SCIP_RETCODE SCIPtpiInitCondition(SCIP_CONDITION **condition)
Definition: tpi_openmp.c:676
SCIP_RETCODE SCIPtpiInit(int nthreads, int queuesize, SCIP_Bool blockwhenfull)
Definition: tpi_openmp.c:595
#define SCIPompInitCondition(condition)
Definition: tpi_openmp.c:49
@ 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