Scippy

SCIP

Solving Constraint Integer Programs

tpi_tnycthrd.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-2017 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file tpi_tnycthrd.c
17  * @ingroup TASKINTERFACE
18  * @brief a TPI implementation using tinycthreads
19  * @author Stephen J. Maher
20  * @author Robert Lion Gottwald
21  */
22 
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24 
25 #include "tpi/tpi.h"
26 #include "blockmemshell/memory.h"
27 
29 static SCIP_THREADPOOL* _threadpool = NULL;
30 _Thread_local int _threadnumber;
31 
32 /** A job added to the queue */
33 struct SCIP_Job
34 {
35  int jobid; /**< id to identify jobs from a common process */
36  struct SCIP_Job* nextjob; /**< pointer to the next job in the queue */
37  SCIP_RETCODE (*jobfunc)(void* args);/**< pointer to the job function */
38  void* args; /**< pointer to the function arguements */
39  SCIP_RETCODE retcode; /**< return code of the job */
40 };
41 
42 /** the thread pool job queue */
43 struct SCIP_JobQueue
44 {
45  SCIP_JOB* firstjob; /**< pointer to the first job in the queue */
46  SCIP_JOB* lastjob; /**< pointer to the last job in the queue */
47  int njobs; /**< number of jobs in the queue */
48 };
50 
51 /** The thread pool */
53 {
54  /* Pool Characteristics */
55  int nthreads; /**< number of threads in the pool */
56  int queuesize; /**< the total number of items to enter the queue */
57 
58  /* Current pool state */
59  thrd_t* threads; /**< the threads included in the pool */
60  SCIP_JOBQUEUE* jobqueue; /**< the job queue */
61  SCIP_JOBQUEUE* currentjobs; /**< the jobs currently being processed on a thread.
62  Only a single job is allowed per thread. */
63  SCIP_JOBQUEUE* finishedjobs; /**< finished jobs that are not yet collected */
64  int currworkingthreads; /**< the threads currently processing jobs */
65  SCIP_Bool blockwhenfull; /**< indicates that the queue can only be as large as nthreads */
66  int currentid; /**< current job id */
67 
68  /* Control indicators */
69  SCIP_Bool shutdown; /**< indicates whether the pool needs to be shutdown */
70  SCIP_Bool queueopen; /**< indicates whether the queue is open */
71 
72  /* mutex and locks for the thread pool */
73  SCIP_LOCK poollock; /**< mutex to allow read and write of the pool features */
74  SCIP_CONDITION queuenotempty; /**< condition to broadcast the queue has jobs */
75  SCIP_CONDITION queuenotfull; /**< condition to broadcast the queue is not full */
76  SCIP_CONDITION queueempty; /**< condition to broadcast that the queue is empty */
77  SCIP_CONDITION jobfinished; /**< condition to broadcast that a job has been finished */
78 };
79 
80 /** this function controls the execution of each of the threads */
81 static
83  void* threadnum /**< thread number is passed in as argument stored inside a void pointer */
84  )
85 {
86  SCIP_JOB* newjob;
87  SCIP_JOB* prevjob;
88  SCIP_JOB* currjob;
89 
90  _threadnumber = (int)(size_t) threadnum;
91 
92  /* Increase the number of active threads */
93  SCIP_CALL( SCIPtpiAcquireLock(&(_threadpool->poollock)) );
94  _threadpool->currworkingthreads += 1;
95  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
96 
97  /* this is an endless loop that runs until the thrd_exit function is called */
98  while( TRUE )
99  {
100  SCIP_CALL( SCIPtpiAcquireLock(&(_threadpool->poollock)) );
101 
102  /* the queue is empty but the shutdown command has not been given */
103  while( _threadpool->jobqueue->njobs == 0 && !_threadpool->shutdown )
104  {
105  SCIP_CALL( SCIPtpiWaitCondition(&(_threadpool->queuenotempty), &(_threadpool->poollock)) );
106  }
107 
108  /* if the shutdown command has been given, the exit the thread */
109  if( _threadpool->shutdown )
110  {
111  /* Decrease the thread count when execution of job queue has completed */
112  _threadpool->currworkingthreads -= 1;
113  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
114 
115  thrd_exit(SCIP_OKAY);
116  }
117 
118  /* getting the next job in the queue */
119  newjob = _threadpool->jobqueue->firstjob;
120  _threadpool->jobqueue->njobs--; /* decreasing the number of jobs in the queue */
121 
122  if( _threadpool->jobqueue->njobs == 0 )
123  {
124  _threadpool->jobqueue->firstjob = NULL;
125  _threadpool->jobqueue->lastjob = NULL;
126  }
127  else
128  _threadpool->jobqueue->firstjob = newjob->nextjob; /* updating the queue */
129 
130  /* if we want to wait when the queue is full, then we broadcast that the queue can now take new jobs */
131  if( _threadpool->blockwhenfull &&
132  _threadpool->jobqueue->njobs == _threadpool->queuesize - 1 )
133  {
135  }
136 
137  /* indicating that the queue is empty */
138  if( _threadpool->jobqueue->njobs == 0 )
139  {
140  SCIP_CALL( SCIPtpiBroadcastCondition(&(_threadpool->queueempty)) );
141  }
142 
143  /* updating the current job list */
144  if( _threadpool->currentjobs->njobs == 0 )
145  {
146  _threadpool->currentjobs->firstjob = newjob;
147  _threadpool->currentjobs->lastjob = newjob;
148  }
149  else
150  {
151  _threadpool->currentjobs->lastjob->nextjob = newjob;
152  _threadpool->currentjobs->lastjob = newjob;
153  }
154 
155  _threadpool->currentjobs->njobs++;
156 
157  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
158 
159  /* setting the job to run on this thread */
160  newjob->retcode = (*(newjob->jobfunc))(newjob->args);
161 
162  /* setting the current job on this thread to NULL */
163  SCIP_CALL( SCIPtpiAcquireLock(&(_threadpool->poollock)) );
164 
165  /* finding the location of the processed job in the currentjobs queue */
166  currjob = _threadpool->currentjobs->firstjob;
167  prevjob = NULL;
168 
169  while( currjob != newjob )
170  {
171  prevjob = currjob;
172  currjob = prevjob->nextjob;
173  }
174 
175  /* removing the processed job from current jobs list */
176  if( currjob == _threadpool->currentjobs->firstjob )
177  _threadpool->currentjobs->firstjob = currjob->nextjob;
178  else
179  prevjob->nextjob = currjob->nextjob;
180 
181  if( currjob == _threadpool->currentjobs->lastjob )
182  _threadpool->currentjobs->lastjob = prevjob;
183 
184  _threadpool->currentjobs->njobs--;
185 
186  /* updating the finished job list */
187  if( _threadpool->finishedjobs->njobs == 0 )
188  {
189  _threadpool->finishedjobs->firstjob = newjob;
190  _threadpool->finishedjobs->lastjob = newjob;
191  }
192  else
193  {
194  _threadpool->finishedjobs->lastjob->nextjob = newjob;
195  _threadpool->finishedjobs->lastjob = newjob;
196  }
197 
198  _threadpool->finishedjobs->njobs++;
199 
200  /* signalling that a job has been finished */
201  SCIP_CALL( SCIPtpiBroadcastCondition(&(_threadpool)->jobfinished) );
202 
203  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
204  }
205 }
206 
207 /** creates a threadpool */
208 static
210  SCIP_THREADPOOL** thrdpool, /**< pointer to store threadpool */
211  int nthreads, /**< number of threads in the threadpool */
212  int qsize, /**< maximum size of the jobqueue */
213  SCIP_Bool blockwhenfull /**< should the jobqueue block if it is full */
214  )
215 {
216  int i;
217 
218  assert(nthreads >= 0);
219  assert(qsize >= 0);
220 
221  /* @todo think about the correct memory here */
222  SCIP_ALLOC( BMSallocMemory(thrdpool) );
223  (*thrdpool)->currentid = 0;
224  (*thrdpool)->queuesize = qsize;
225  (*thrdpool)->nthreads = nthreads;
226  (*thrdpool)->blockwhenfull = blockwhenfull;
227  (*thrdpool)->shutdown = FALSE;
228  (*thrdpool)->queueopen = TRUE;
229 
230  /* allocating memory for the job queue */
231  SCIP_ALLOC( BMSallocMemory(&(*thrdpool)->jobqueue) );
232  (*thrdpool)->jobqueue->firstjob = NULL;
233  (*thrdpool)->jobqueue->lastjob = NULL;
234  (*thrdpool)->jobqueue->njobs = 0;
235 
236  /* allocating memory for the job queue */
237  SCIP_ALLOC( BMSallocMemory(&(*thrdpool)->currentjobs) );
238  (*thrdpool)->currentjobs->firstjob = NULL;
239  (*thrdpool)->currentjobs->lastjob = NULL;
240  (*thrdpool)->currentjobs->njobs = 0;
241 
242  /* allocating memory for the job queue */
243  SCIP_ALLOC( BMSallocMemory(&(*thrdpool)->finishedjobs) );
244  (*thrdpool)->finishedjobs->firstjob = NULL;
245  (*thrdpool)->finishedjobs->lastjob = NULL;
246  (*thrdpool)->finishedjobs->njobs = 0;
247 
248  /* initialising the mutex */
249  SCIP_CALL( SCIPtpiInitLock(&(*thrdpool)->poollock) );
250 
251  /* initialising the conditions */
252  SCIP_CALL( SCIPtpiInitCondition(&(*thrdpool)->queuenotempty) );
253  SCIP_CALL( SCIPtpiInitCondition(&(*thrdpool)->queuenotfull) );
254  SCIP_CALL( SCIPtpiInitCondition(&(*thrdpool)->queueempty) );
255  SCIP_CALL( SCIPtpiInitCondition(&(*thrdpool)->jobfinished) );
256 
257  /* creating the threads */
258  (*thrdpool)->currworkingthreads = 0;
259 
260  /* allocating memory for the threads */
261  SCIP_ALLOC( BMSallocMemoryArray(&((*thrdpool)->threads), nthreads) );
262 
263  /* create the threads */
264  for( i = 0; i < nthreads; i++ )
265  {
266  if( thrd_create(&((*thrdpool)->threads[i]), threadPoolThread, (void*)(size_t)i) != thrd_success )
267  return SCIP_ERROR;
268  }
269 
270  _threadnumber = nthreads;
271  /* halt while all threads are not active TODO: is synchronization required here ? */
272  /*TODO: this caused a deadlock, is it important to wait for all threads to start?
273  * while( (*thrdpool)->currworkingthreads != nthreads )
274  {}*/
275 
276  return SCIP_OKAY;
277 }
278 
279 /** adding a job to the job queue.
280  * This gives some more flexibility in the handling of new jobs.
281  * This function needs to be called from within a mutex. */
282 static
284  SCIP_THREADPOOL* threadpool,
285  SCIP_JOB* newjob
286  )
287 {
288  /* @todo we want to work out what to do with a full job queue. Is there a problem if the limit is hit? */
289  /* @note it is important to have a queuesize. This will stop the code submitting infinitely many jobs. */
290  assert(threadpool->jobqueue->njobs < threadpool->queuesize);
291 
292  newjob->nextjob = NULL;
293 
294  /* checking the status of the job queue */
295  if( threadpool->jobqueue->njobs == 0 )
296  {
297  threadpool->jobqueue->firstjob = newjob;
298  threadpool->jobqueue->lastjob = newjob;
299  }
300  else /* it is assumed that the jobqueue is not full */
301  {
302  threadpool->jobqueue->lastjob->nextjob = newjob;
303  threadpool->jobqueue->lastjob = newjob;
304  }
305 
306  SCIP_CALL_ABORT( SCIPtpiSignalCondition(&(threadpool->queuenotempty)) ); /* signalling to all threads that the queue has jobs
307  * using the signal instead of broadcast because only one
308  * thread should be awakened */
309 
310  threadpool->jobqueue->njobs++;
311 }
312 
313 /** adds a job to the threadpool */
314 static
316  SCIP_JOB* newjob, /**< job to add to threadpool */
317  SCIP_SUBMITSTATUS* status /**< pointer to store the job's submit status */
318  )
319 {
320  assert(newjob != NULL);
321  assert(_threadpool != NULL);
322 
323  SCIP_CALL( SCIPtpiAcquireLock(&(_threadpool->poollock)) );
324 
325  /* if the queue is full and we are blocking, then return an error. */
326  if( _threadpool->jobqueue->njobs == _threadpool->queuesize && _threadpool->blockwhenfull )
327  {
328  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
329  *status = SCIP_SUBMIT_QUEUEFULL;
330  return SCIP_OKAY;
331  }
332 
333  /* Wait until the job queue is not full. If the queue is closed or the thread pool is shutdown, then stop waiting */
334  /* @todo this needs to be checked. It is possible that a job can be submitted and then the queue is closed or the
335  * thread pool is shutdown. Need to work out the best way to handle this. */
336  while( _threadpool->jobqueue->njobs == _threadpool->queuesize && !(_threadpool->shutdown || !_threadpool->queueopen) )
337  {
338  SCIP_CALL( SCIPtpiWaitCondition(&(_threadpool->queuenotfull), &(_threadpool->poollock)) );
339  }
340 
341  /* if the thread pool is shutdown or the queue is closed, then we need to leave the job submission */
342  if( !_threadpool->queueopen )
343  {
344  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
345  *status = SCIP_SUBMIT_QUEUECLOSED;
346  return SCIP_OKAY;
347  }
348  else if( _threadpool->shutdown )
349  {
350  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
351  *status = SCIP_SUBMIT_SHUTDOWN;
352  return SCIP_OKAY;
353  }
354 
355  /* creating the job for submission */
356  newjob->nextjob = NULL;
357 
358  /* adding the job to the queue */
359  /* this can only happen if the queue is not full
360  */
361  assert(_threadpool->jobqueue->njobs != _threadpool->queuesize);
362  jobQueueAddJob(_threadpool, newjob);
363 
364  SCIP_CALL( SCIPtpiReleaseLock(&(_threadpool->poollock)) );
365 
366  *status = SCIP_SUBMIT_SUCCESS;
367  return SCIP_OKAY;;
368 }
369 
370 /** frees the jobqueue of the threadpool */
371 static
373  SCIP_THREADPOOL* thrdpool
374  )
375 {
376  SCIP_JOB* currjob;
377 
378  assert(!thrdpool->queueopen);
379  assert(thrdpool->shutdown);
380 
381  /* iterating through all jobs until all have been freed. */
382  while( thrdpool->jobqueue->firstjob != NULL )
383  {
384  currjob = thrdpool->jobqueue->firstjob->nextjob;
385  thrdpool->jobqueue->firstjob = thrdpool->jobqueue->firstjob->nextjob;
386  BMSfreeMemory(&currjob);
387  }
388 
389  assert(thrdpool->jobqueue->firstjob == NULL);
390  assert(thrdpool->jobqueue->lastjob == NULL);
391 
392  BMSfreeMemory(&thrdpool->jobqueue);
393 }
394 
395 
396 
397 
398 static
400  SCIP_THREADPOOL** thrdpool,
401  SCIP_Bool finishjobs,
402  SCIP_Bool completequeue
403  )
404 {
405  int i;
407 
408  /*TODO remove argument? */
409  SCIP_UNUSED( finishjobs );
410 
411  SCIP_CALL( SCIPtpiAcquireLock(&((*thrdpool)->poollock)) );
412 
413  /* if the shutdown is already in progress, then we don't need to completed this function */
414  if( !(*thrdpool)->queueopen || (*thrdpool)->shutdown )
415  {
416  SCIP_CALL( SCIPtpiReleaseLock(&((*thrdpool)->poollock)) );
417 
418  return SCIP_OKAY;
419  }
420 
421  /* indicating that the job queue is now closed for new jobs */
422  (*thrdpool)->queueopen = FALSE;
423 
424  /* if the jobs in the queue should be completed, then we wait until the queueempty condition is set */
425  if( completequeue )
426  {
427  while( (*thrdpool)->jobqueue->njobs > 0 )
428  {
429  SCIP_CALL( SCIPtpiWaitCondition(&((*thrdpool)->queueempty), &((*thrdpool)->poollock)) );
430  }
431  }
432 
433  /* indicating that the tpi has commenced the shutdown process */
434  (*thrdpool)->shutdown = TRUE;
435 
436  SCIP_CALL( SCIPtpiReleaseLock(&((*thrdpool)->poollock)) );
437 
438  /* waking up all threads so that they can check the shutdown condition
439  * this requires that the conditions queuenotempty and queuenotfull is broadcast
440  */
441  SCIP_CALL( SCIPtpiBroadcastCondition(&((*thrdpool)->queuenotempty)) );
442  SCIP_CALL( SCIPtpiBroadcastCondition(&((*thrdpool)->queuenotfull)) );
443 
444  retcode = SCIP_OKAY;
445 
446  /* calling a join to ensure that all worker finish before the thread pool is closed */
447  for( i = 0; i < (*thrdpool)->nthreads; i++ )
448  {
449  int thrdretcode;
450 
451  if( thrd_join((*thrdpool)->threads[i], &thrdretcode) != thrd_success )
452  retcode = (SCIP_RETCODE) MIN(SCIP_ERROR, retcode);
453  else
454  retcode = (SCIP_RETCODE) MIN(thrdretcode, retcode);
455  }
456 
457  /* freeing memory and data structures */
458  BMSfreeMemoryArray(&(*thrdpool)->threads);
459 
460  /* freeing the current jobs list. This assumes that all jobs complete before the tpi is closed. */
461  assert((*thrdpool)->currentjobs->njobs == 0);
462  BMSfreeMemory(&(*thrdpool)->currentjobs);
463  assert((*thrdpool)->finishedjobs->njobs == 0);
464  BMSfreeMemory(&(*thrdpool)->finishedjobs);
465 
466  freeJobQueue(*thrdpool);
467 
468  /* destroying the conditions */
469  SCIPtpiDestroyCondition(&(*thrdpool)->jobfinished);
470  SCIPtpiDestroyCondition(&(*thrdpool)->queueempty);
471  SCIPtpiDestroyCondition(&(*thrdpool)->queuenotfull);
472  SCIPtpiDestroyCondition(&(*thrdpool)->queuenotempty);
473 
474  /* destroying the mutex */
475  SCIPtpiDestroyLock(&(*thrdpool)->poollock);
476 
477  BMSfreeMemory(thrdpool);
478 
479  return retcode;
480 }
481 
482 
483 /* checking a job queue */
484 static
486  SCIP_JOBQUEUE* jobqueue,
487  int jobid
488  )
489 {
490  SCIP_JOB* currjob = jobqueue->firstjob;
491 
492  /* checking the job ids */
493  if( currjob != NULL )
494  {
495  while( currjob != jobqueue->lastjob )
496  {
497  if( currjob->jobid == jobid )
498  return SCIP_JOB_INQUEUE;
499 
500  currjob = currjob->nextjob;
501  }
502 
503  if( currjob->jobid == jobid )
504  return SCIP_JOB_INQUEUE;
505  }
506 
507  return SCIP_JOB_DOESNOTEXIST;
508 }
509 
510 
511 
512 /* returns whether the job id is running */
513 static
515  SCIP_JOBQUEUE* currentjobs,
516  int jobid
517  )
518 {
519  if( checkJobQueue(currentjobs, jobid) == SCIP_JOB_INQUEUE )
520  return TRUE;
521  else
522  return FALSE;
523 }
524 
525 /** returns the number of threads */
527  void
528  )
529 {
530  return _threadpool->nthreads;
531 }
532 
533 /** initializes tpi */
535  int nthreads,
536  int queuesize,
537  SCIP_Bool blockwhenfull
538  )
539 {
540  assert(_threadpool == NULL);
541  SCIP_CALL( createThreadPool(&_threadpool, nthreads, queuesize, blockwhenfull) );
542  return SCIP_OKAY;
543 }
544 
545 /** deinitializes tpi */
547  void
548  )
549 {
550  assert(_threadpool != NULL);
551 
552  SCIP_CALL( freeThreadPool(&_threadpool, TRUE, TRUE) );
553 
554  return SCIP_OKAY;
555 }
556 
557 
558 /** creates a job for parallel processing*/
560  SCIP_JOB** job, /**< pointer to the job that will be created */
561  int jobid, /**< the id for the current job */
562  SCIP_RETCODE (*jobfunc)(void* args),/**< pointer to the job function */
563  void* jobarg /**< the job's argument */
564  )
565 {
566  SCIP_ALLOC( BMSallocMemory(job) );
567 
568  (*job)->jobid = jobid;
569  (*job)->jobfunc = jobfunc;
570  (*job)->args = jobarg;
571  (*job)->nextjob = NULL;
572 
573  return SCIP_OKAY;
574 }
575 
576 /** get a new job id for the new set of submitted jobs */
578  void
579  )
580 {
581  int id;
582  assert(_threadpool != NULL);
583 
584  SCIP_CALL_ABORT( SCIPtpiAcquireLock(&_threadpool->poollock) );
585  id = ++_threadpool->currentid;
586  SCIP_CALL_ABORT( SCIPtpiReleaseLock(&_threadpool->poollock) );
587 
588  return id;
589 }
590 
591 /** submit a job for parallel processing
592  * the return is a globally defined status */
594  SCIP_JOB* job, /**< pointer to the job to be submitted */
595  SCIP_SUBMITSTATUS* status /**< pointer to store the job's submit status */
596  )
597 {
598  assert(job != NULL);
599 
600  assert(job->jobid == _threadpool->currentid); /* the job id must be set before submitting the job. The submitter controls
601  whether a new id is required. */
602 
603  SCIP_CALL( threadPoolAddWork(job, status) );
604 
605  return SCIP_OKAY;
606 }
607 
608 
609 /** blocks until all jobs of the given jobid have finished
610  * and then returns the smallest SCIP_RETCODE of all the jobs
611  */
613  int jobid /**< the jobid of the jobs to wait for */
614  )
615 {
617  SCIP_JOB* currjob;
618  SCIP_JOB* prevjob;
619 
620  SCIP_CALL( SCIPtpiAcquireLock(&(_threadpool->poollock)) );
621 
622  while( isJobRunning(_threadpool->currentjobs, jobid) ||
623  isJobRunning(_threadpool->jobqueue, jobid) )
624  {
625  SCIP_CALL( SCIPtpiWaitCondition(&_threadpool->jobfinished, &_threadpool->poollock) );
626  }
627 
628  /* finding the location of the processed job in the currentjobs queue */
629  retcode = SCIP_OKAY;
630  currjob = _threadpool->finishedjobs->firstjob;
631  prevjob = NULL;
632 
633  while( currjob )
634  {
635  if( currjob->jobid == jobid )
636  {
637  SCIP_JOB* nextjob;
638 
639  /* if the job has the right jobid collect its retcode,
640  * remove it from the finished job list, and free it
641  */
642  retcode = MIN(retcode, currjob->retcode);
643 
644  /* removing the finished job from finished jobs list */
645  if( currjob == _threadpool->finishedjobs->firstjob )
646  {
647  _threadpool->finishedjobs->firstjob = currjob->nextjob;
648  }
649  else
650  {
651  assert(prevjob != NULL);
652  prevjob->nextjob = currjob->nextjob;
653  }
654 
655  if( currjob == _threadpool->finishedjobs->lastjob )
656  _threadpool->finishedjobs->lastjob = prevjob;
657 
658  _threadpool->finishedjobs->njobs--;
659 
660  /* update currjob and free finished job; prevjob stays the same */
661  nextjob = currjob->nextjob;
662  BMSfreeMemory(&currjob);
663  currjob = nextjob;
664  }
665  else
666  {
667  /* otherwise leave job untouched */
668  prevjob = currjob;
669  currjob = prevjob->nextjob;
670  }
671  }
672 
673  SCIP_CALL( SCIPtpiReleaseLock(&_threadpool->poollock) );
674 
675  return retcode;
676 }
SCIP_RETCODE SCIPtpiWaitCondition(SCIP_CONDITION *condition, SCIP_LOCK *lock)
Definition: tpi_openmp.c:286
static int threadPoolThread(void *threadnum)
Definition: tpi_tnycthrd.c:82
SCIP_CONDITION queuenotempty
Definition: tpi_tnycthrd.c:74
enum SCIP_Submitstatus SCIP_SUBMITSTATUS
Definition: type_tpi.h:45
SCIP_JOB * firstjob
Definition: tpi_openmp.c:41
#define FALSE
Definition: def.h:64
enum SCIP_Jobstatus SCIP_JOBSTATUS
Definition: type_tpi.h:60
void * args
Definition: tpi_openmp.c:34
static SCIP_JOBSTATUS checkJobQueue(SCIP_JOBQUEUE *jobqueue, int jobid)
Definition: tpi_tnycthrd.c:485
#define TRUE
Definition: def.h:63
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_RETCODE SCIPtpiBroadcastCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:274
SCIP_RETCODE SCIPtpiAcquireLock(SCIP_LOCK *lock)
#define SCIP_UNUSED(x)
Definition: def.h:360
#define BMSallocMemoryArray(ptr, num)
Definition: memory.h:78
SCIP_RETCODE SCIPtpiInitCondition(SCIP_LOCK *lock)
SCIP_JOB * lastjob
Definition: tpi_openmp.c:42
SCIP_JOBQUEUE * finishedjobs
Definition: tpi_tnycthrd.c:63
static SCIP_RETCODE createThreadPool(SCIP_THREADPOOL **thrdpool, int nthreads, int qsize, SCIP_Bool blockwhenfull)
Definition: tpi_tnycthrd.c:209
#define BMSfreeMemory(ptr)
Definition: memory.h:100
SCIP_JOBQUEUE * jobqueue
Definition: tpi_tnycthrd.c:60
thrd_t * threads
Definition: tpi_tnycthrd.c:59
SCIP_CONDITION queueempty
Definition: tpi_tnycthrd.c:76
SCIP_RETCODE SCIPtpiCreateJob(SCIP_JOB **job, int jobid, SCIP_RETCODE(*jobfunc)(void *args), void *jobarg)
Definition: tpi_tnycthrd.c:559
SCIP_RETCODE SCIPtpiInit(int nthreads, int queuesize, SCIP_Bool blockwhenfull)
Definition: tpi_tnycthrd.c:534
SCIP_JOBQUEUE * currentjobs
Definition: tpi_tnycthrd.c:61
#define BMSfreeMemoryArray(ptr)
Definition: memory.h:102
SCIP_RETCODE SCIPtpiReleaseLock(SCIP_LOCK *lock)
the type definitions for the SCIP parallel interface
SCIP_Bool blockwhenfull
Definition: tpi_tnycthrd.c:65
SCIP_RETCODE retcode
Definition: tpi_openmp.c:35
SCIP_Bool queueopen
Definition: tpi_tnycthrd.c:70
struct SCIP_Job * nextjob
Definition: tpi_openmp.c:32
SCIP_CONDITION queuenotfull
Definition: tpi_tnycthrd.c:75
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_RETCODE SCIPtpiExit(void)
Definition: tpi_tnycthrd.c:546
#define SCIP_CALL(x)
Definition: def.h:306
int jobid
Definition: tpi_openmp.c:31
int SCIPtpiGetNumThreads(void)
Definition: tpi_tnycthrd.c:526
#define SCIP_Bool
Definition: def.h:61
SCIP_RETCODE SCIPtpiInitLock(SCIP_LOCK *lock)
SCIP_LOCK poollock
Definition: tpi_tnycthrd.c:73
SCIP_Bool shutdown
Definition: tpi_tnycthrd.c:69
void SCIPtpiDestroyLock(SCIP_LOCK *lock)
void SCIPtpiDestroyCondition(SCIP_LOCK *lock)
static SCIP_RETCODE threadPoolAddWork(SCIP_JOB *newjob, SCIP_SUBMITSTATUS *status)
Definition: tpi_tnycthrd.c:315
SCIP_RETCODE SCIPtpiSignalCondition(SCIP_CONDITION *condition)
Definition: tpi_openmp.c:260
static SCIP_RETCODE freeThreadPool(SCIP_THREADPOOL **thrdpool, SCIP_Bool finishjobs, SCIP_Bool completequeue)
Definition: tpi_tnycthrd.c:399
#define MIN(x, y)
Definition: memory.c:75
static void freeJobQueue(SCIP_THREADPOOL *thrdpool)
Definition: tpi_tnycthrd.c:372
#define BMSallocMemory(ptr)
Definition: memory.h:74
SCIP_RETCODE(* jobfunc)(void *args)
Definition: tpi_openmp.c:33
SCIP_RETCODE SCIPtpiCollectJobs(int jobid)
Definition: tpi_tnycthrd.c:612
#define SCIP_CALL_ABORT(x)
Definition: def.h:285
SCIP_RETCODE SCIPtpiSumbitJob(SCIP_JOB *job, SCIP_SUBMITSTATUS *status)
Definition: tpi_tnycthrd.c:593
#define SCIP_ALLOC(x)
Definition: def.h:317
static SCIP_Bool isJobRunning(SCIP_JOBQUEUE *currentjobs, int jobid)
Definition: tpi_tnycthrd.c:514
int SCIPtpiGetNewJobID(void)
Definition: tpi_tnycthrd.c:577
static void jobQueueAddJob(SCIP_THREADPOOL *threadpool, SCIP_JOB *newjob)
Definition: tpi_tnycthrd.c:283
SCIP_CONDITION jobfinished
Definition: tpi_tnycthrd.c:77
memory allocation routines