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"
36 #include "blockmemshell/memory.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 */
55 struct SCIP_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 */
71 struct SCIP_Job
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 
101 static SCIP_JOBQUEUES* _jobqueues = NULL;
102 
103 
104 /** create job queue */
105 static
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;
129  SCIP_ALLOC( BMSallocMemoryArray(&_jobqueues->currentjobs, nthreads) );
130 
131  for( i = 0; i < nthreads; ++i )
132  _jobqueues->currentjobs[i] = NULL;
133 
134  SCIP_CALL( SCIPompInitLock(&_jobqueues->lock) );
135  SCIP_CALL( SCIPompInitCondition(&_jobqueues->jobfinished) );
136 
137  return SCIP_OKAY;
138 }
139 
140 
141 /** free job queue */
142 static
144  void
145  )
146 {
147  assert(_jobqueues != NULL);
148 
149  SCIPompDestroyLock(&_jobqueues->lock);
150  SCIPompDestroyCondition(&_jobqueues->jobfinished);
151  BMSfreeMemoryArray(&_jobqueues->currentjobs);
152 
153  BMSfreeMemory(&_jobqueues);
154 
155  return SCIP_OKAY;
156 }
157 
158 
159 /** execute job */
160 static
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 
206  SCIP_CALL( SCIPtpiReleaseLock(lock) );
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 
231  SCIP_CALL( SCIPtpiAcquireLock(lock) );
232 
233  return SCIP_OKAY;
234 }
235 
236 /** wait for a condition (direct access to lock) */
237 static
239  SCIP_CONDITION* condition, /**< condition to wait for */
240  omp_lock_t* lock /**< corresponding lock */
241  )
242 {
243  int waitnum;
244 
245  SCIP_CALL( SCIPompReleaseLock(lock) );
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 
270  SCIP_CALL( SCIPompAcquireLock(lock) );
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  */
281 static
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  */
328 static
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 {
436  SCIP_ALLOC( BMSallocMemory(job) );
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;
469  SCIP_CALL( jobQueueAddJob(job) );
470 
471  return SCIP_OKAY;
472 }
473 
474 
475 /** check whether a job is running */
476 static
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 */
497 static
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 
619  SCIP_CALL( freeJobQueue() );
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 
636  SCIP_ALLOC( BMSallocMemory(lock) );
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);
649  BMSfreeMemory(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 }
SCIP_RETCODE SCIPtpiReleaseLock(SCIP_LOCK *lock)
Definition: tpi_openmp.c:662
#define NULL
Definition: def.h:267
void SCIPtpiDestroyLock(SCIP_LOCK **lock)
Definition: tpi_openmp.c:642
#define SCIPompReleaseLock(lock)
Definition: tpi_openmp.c:46
enum SCIP_Submitstatus SCIP_SUBMITSTATUS
Definition: type_tpi.h:50
static SCIP_RETCODE SCIPompWaitCondition(SCIP_CONDITION *condition, omp_lock_t *lock)
Definition: tpi_openmp.c:238
SCIP_JOB * firstjob
Definition: tpi_openmp.c:83
SCIP_RETCODE SCIPtpiCreateJob(SCIP_JOB **job, int jobid, SCIP_RETCODE(*jobfunc)(void *args), void *jobarg)
Definition: tpi_openmp.c:429
#define FALSE
Definition: def.h:94
void * args
Definition: tpi_openmp.c:76
#define TRUE
Definition: def.h:93
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
#define SCIP_UNUSED(x)
Definition: def.h:434
#define SCIPompDestroyCondition(condition)
Definition: tpi_openmp.c:51
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:123
void SCIPtpiDestroyCondition(SCIP_CONDITION **condition)
Definition: tpi_openmp.c:693
SCIP_RETCODE SCIPtpiCollectJobs(int jobid)
Definition: tpi_openmp.c:526
SCIP_JOB * lastjob
Definition: tpi_openmp.c:84
static SCIP_Bool isJobRunning(int jobid)
Definition: tpi_openmp.c:477
SCIP_RETCODE SCIPtpiInit(int nthreads, int queuesize, SCIP_Bool blockwhenfull)
Definition: tpi_openmp.c:595
#define BMSfreeMemory(ptr)
Definition: memory.h:145
static void jobQueueProcessJob(void)
Definition: tpi_openmp.c:282
static SCIP_RETCODE createJobQueue(int nthreads, int qsize, SCIP_Bool blockwhenfull)
Definition: tpi_openmp.c:106
static SCIP_RETCODE jobQueueAddJob(SCIP_JOB *newjob)
Definition: tpi_openmp.c:329
int SCIPtpiGetThreadNum()
Definition: tpi_openmp.c:422
SCIP_RETCODE SCIPtpiSignalCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:381
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:147
the type definitions for the SCIP parallel interface
SCIP_RETCODE retcode
Definition: tpi_openmp.c:77
SCIP_RETCODE SCIPtpiInitLock(SCIP_LOCK **lock)
Definition: tpi_openmp.c:630
struct SCIP_Job * nextjob
Definition: tpi_openmp.c:74
SCIP_RETCODE SCIPtpiExit(void)
Definition: tpi_openmp.c:610
SCIP_RETCODE SCIPtpiSubmitJob(SCIP_JOB *job, SCIP_SUBMITSTATUS *status)
Definition: tpi_openmp.c:461
#define SCIP_CALL(x)
Definition: def.h:380
static SCIP_Bool isJobWaiting(int jobid)
Definition: tpi_openmp.c:498
int jobid
Definition: tpi_openmp.c:73
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
SCIP_CONDITION jobfinished
Definition: tpi_openmp.c:97
#define SCIPompAcquireLock(lock)
Definition: tpi_openmp.c:45
SCIP_JOBQUEUE jobqueue
Definition: tpi_openmp.c:91
#define SCIPompInitCondition(condition)
Definition: tpi_openmp.c:49
SCIP_RETCODE SCIPtpiAcquireLock(SCIP_LOCK *lock)
Definition: tpi_openmp.c:653
public methods for message output
int SCIPtpiGetNumThreads()
Definition: tpi_openmp.c:415
SCIP_RETCODE SCIPtpiInitCondition(SCIP_CONDITION **condition)
Definition: tpi_openmp.c:676
#define BMSallocMemory(ptr)
Definition: memory.h:118
SCIP_RETCODE(* jobfunc)(void *args)
Definition: tpi_openmp.c:75
SCIP_JOB ** currentjobs
Definition: tpi_openmp.c:92
SCIP_RETCODE SCIPtpiBroadcastCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:399
SCIP_RETCODE SCIPtpiWaitCondition(SCIP_CONDITION *condition, SCIP_LOCK *lock)
Definition: tpi_openmp.c:199
#define SCIPompInitLock(lock)
Definition: tpi_openmp.c:43
omp_lock_t lock
Definition: tpi_openmp.c:96
static void executeJob(SCIP_JOB *job)
Definition: tpi_openmp.c:161
#define SCIP_CALL_ABORT(x)
Definition: def.h:359
int SCIPtpiGetNewJobID(void)
Definition: tpi_openmp.c:447
static SCIP_RETCODE freeJobQueue(void)
Definition: tpi_openmp.c:143
#define SCIP_ALLOC(x)
Definition: def.h:391
#define SCIPompDestroyLock(lock)
Definition: tpi_openmp.c:44
SCIP_JOBQUEUE finishedjobs
Definition: tpi_openmp.c:95
omp_lock_t lock
Definition: tpi_openmp.c:57
memory allocation routines