user623982
user623982

Reputation: 1

Multithreading program

basically my program has 2 sets of threads, workers and jobs. Each job has an arrival time, then it is pushed onto a queue.

For the servers, I want them to constantly look for a job on the queue, once there is a job on the queue, only 1 worker takes it off and does its thing with it.

In main, all the worker threads are created first and then the job threads are created and synchronized (each pushing stuff on the queue). I can't get the timing right as the worker threads sometimes do things at exactly the same time OR the jobs aren't being pushed onto the queue at the right times (ie. job with arrival time 3 is pushed before job with arrival time 2). How can I do this using semaphores and/or mutexes?

I tried to put a mutex in the worker function but I don't really have a good handle on mutexes/semaphores..

Any ideas would be appreciated.

Thanks!

Upvotes: 0

Views: 295

Answers (3)

ali_bahoo
ali_bahoo

Reputation: 4863

Copied from an answer to one of my earlier questions. My question concerns Win32 threads but the described consept pretty much the same with pthreads.

  1. Use a semaphore in your queue to indicate whether there are elements ready to be processed.
  2. Every time you add an item, call sem_post() to increment the count associated with the semaphore
  3. In the loop in your thread process, call sem_wait() on the handle of your semaphore object

Here is a tutorial for POSIX Semaphores

But first like the other guy said, you have to make Q thread-safe.

void *func(void *newWorker) {
    struct workerType* worker = (struct workerType*) newWorker;
    while(numServed < maxJobs) {
        //if(!Q.empty()) {
        // No need to ask if Q is empty.
        // If a thread passes the sem_wait function 
        // there has to be at least one job in the Q 
        sem_wait(&semaphore);
        pthread_mutex_lock(&mutex);
        struct jobType* job = Q.front();
        numServed++;
        cout << job->jobNum << " was served by " << worker->workerNum << endl;
        Q.pop();
        pthread_mutex_unlock(&mutex);
        //sleep(worker->runTime); No need to sleep also        
        //}
    }
}


void *job(void *jobdata) {
    struct jobType *job = (struct jobType*) jobdata;
    //sleep(job->arrivtime);
    pthread_mutex_lock(&mutex);
    Q.push(job);
    pthread_mutex_unlock(&mutex);
    sem_post(&semaphore);
    // Inform the workers that another job is pushed.
}

Upvotes: 1

Umashankar Das
Umashankar Das

Reputation: 601

The Q push to Q pop operation needs to be atomic i.e (is the Critical section). Put that under a Mutex acquire and Mutex release. That should do it for you.

Check the posix thread tutorial to understand mutex acquisition and release. I use this PTHREAD TUTORIAL

Upvotes: 1

Chris Dodd
Chris Dodd

Reputation: 126203

The problem is that your servers are doing three non-atomic queue operations (empty, then front, then pop) with no synchronization to ensure that some other thread doesn't interleave its operations. You need to acquire a mutex or semaphore before calling Q.empty and release it after calling Q.pop to ensure that the empty/front/pop trio is done atomically. You also need to make sure you release the mutux properly if Q.empty fails

Upvotes: 0

Related Questions