static int thread_loop(ESL_THREADS *obj, ESL_WORK_QUEUE *queue, P7_HMMFILE *hfp) { int status = eslOK; int sstatus = eslOK; int eofCount = 0; P7_OM_BLOCK *block; ESL_ALPHABET *abc = NULL; void *newBlock; esl_workqueue_Reset(queue); esl_threads_WaitForStart(obj); status = esl_workqueue_ReaderUpdate(queue, NULL, &newBlock); if (status != eslOK) esl_fatal("Work queue reader failed"); /* Main loop: */ while (sstatus == eslOK) { block = (P7_OM_BLOCK *) newBlock; sstatus = p7_oprofile_ReadBlockMSV(hfp, &abc, block); if (sstatus == eslEOF) { if (eofCount < esl_threads_GetWorkerCount(obj)) sstatus = eslOK; ++eofCount; } if (sstatus == eslOK) { status = esl_workqueue_ReaderUpdate(queue, block, &newBlock); if (status != eslOK) esl_fatal("Work queue reader failed"); } } status = esl_workqueue_ReaderUpdate(queue, block, NULL); if (status != eslOK) esl_fatal("Work queue reader failed"); if (sstatus == eslEOF) { /* wait for all the threads to complete */ esl_threads_WaitForFinish(obj); esl_workqueue_Complete(queue); } esl_alphabet_Destroy(abc); return sstatus; }
static int thread_loop(ESL_THREADS *obj, ESL_WORK_QUEUE *queue, struct cfg_s *cfg) { int status = eslOK; int sstatus = eslOK; int processed = 0; WORK_ITEM *item; void *newItem; int next = 1; PENDING_ITEM *top = NULL; PENDING_ITEM *empty = NULL; PENDING_ITEM *tmp = NULL; char errmsg[eslERRBUFSIZE]; esl_workqueue_Reset(queue); esl_threads_WaitForStart(obj); status = esl_workqueue_ReaderUpdate(queue, NULL, &newItem); if (status != eslOK) esl_fatal("Work queue reader failed"); /* Main loop: */ item = (WORK_ITEM *) newItem; while (sstatus == eslOK) { sstatus = esl_msa_Read(cfg->afp, &item->msa); if (sstatus == eslOK) { item->nali = ++cfg->nali; if (set_msa_name(cfg, errmsg, item->msa) != eslOK) p7_Fail("%s\n", errmsg); } if (sstatus == eslEOF && processed < cfg->nali) sstatus = eslOK; if (sstatus == eslOK) { status = esl_workqueue_ReaderUpdate(queue, item, &newItem); if (status != eslOK) esl_fatal("Work queue reader failed"); /* process any results */ item = (WORK_ITEM *) newItem; if (item->processed == TRUE) { ++processed; /* try to keep the input output order the same */ if (item->nali == next) { sstatus = output_result(cfg, errmsg, item->nali, item->msa, item->hmm, item->postmsa, item->entropy); if (sstatus != eslOK) p7_Fail(errmsg); p7_hmm_Destroy(item->hmm); esl_msa_Destroy(item->msa); esl_msa_Destroy(item->postmsa); ++next; /* output any pending msa as long as the order * remains the same as read in. */ while (top != NULL && top->nali == next) { sstatus = output_result(cfg, errmsg, top->nali, top->msa, top->hmm, top->postmsa, top->entropy); if (sstatus != eslOK) p7_Fail(errmsg); p7_hmm_Destroy(top->hmm); esl_msa_Destroy(top->msa); esl_msa_Destroy(top->postmsa); tmp = top; top = tmp->next; tmp->next = empty; empty = tmp; ++next; } } else { /* queue up the msa so the sequence order is the same in * the .sto and .hmm */ if (empty != NULL) { tmp = empty; empty = tmp->next; } else { ESL_ALLOC(tmp, sizeof(PENDING_ITEM)); } tmp->nali = item->nali; tmp->hmm = item->hmm; tmp->msa = item->msa; tmp->postmsa = item->postmsa; tmp->entropy = item->entropy; /* add the msa to the pending list */ if (top == NULL || tmp->nali < top->nali) { tmp->next = top; top = tmp; } else { PENDING_ITEM *ptr = top; while (ptr->next != NULL && tmp->nali > ptr->next->nali) { ptr = ptr->next; } tmp->next = ptr->next; ptr->next = tmp; } } item->nali = 0; item->processed = FALSE; item->hmm = NULL; item->msa = NULL; item->postmsa = NULL; item->entropy = 0.0; } } } if (top != NULL) esl_fatal("Top is not empty\n"); while (empty != NULL) { tmp = empty; empty = tmp->next; free(tmp); } status = esl_workqueue_ReaderUpdate(queue, item, NULL); if (status != eslOK) esl_fatal("Work queue reader failed"); if (sstatus == eslEOF) { /* wait for all the threads to complete */ esl_threads_WaitForFinish(obj); esl_workqueue_Complete(queue); } return sstatus; ERROR: return eslEMEM; }
int main(void) { int i; int ncpu = 4; int iter = 25; WORK_INFO *worker = NULL; ESL_THREADS *thr = NULL; ESL_WORK_QUEUE *queue = NULL; int *objs = NULL; int *obj; objs = malloc(sizeof(int) * ncpu * 2); worker = malloc(sizeof(WORK_INFO) * ncpu); thr = esl_threads_Create(&worker_thread); /* Create a work queue that is able to hold two items per thread. * The idea is that while one object is being processed by a * worker thread, another item is being readied. So, when the * worker thread has completed processing its current object, * its next object to processes is hopefully waiting. */ queue = esl_workqueue_Create(ncpu * 2); for (i = 0; i < ncpu * 2; i++) { objs[i] = 0; esl_workqueue_Init(queue, &objs[i]); } for (i = 0; i < ncpu; i++) { worker[i].id = 'A' + i; worker[i].queue = queue; esl_threads_AddThread(thr, (void *) &worker[i]); } esl_threads_WaitForStart (thr); /* For N number of iterations, get an object that has been * processed, i.e. on the readers input queue and place it * on the ready queue. */ esl_workqueue_ReaderUpdate(queue, NULL, (void **) &obj); for (i = 1; i <= iter; ++i) { *obj = i; printf("Item %d is ready to be processed\n", *obj); esl_workqueue_ReaderUpdate(queue, obj, (void **) &obj); } /* put zeros on the queues to signal the worker that we are done */ for (i = 0; i < ncpu; ++i) { *obj = 0; esl_workqueue_ReaderUpdate(queue, obj, (void **) &obj); } /* The worker threads now run their work. */ esl_threads_WaitForFinish(thr); esl_threads_Destroy(thr); esl_workqueue_Destroy(queue); free(worker); free(objs); return eslOK; }