← index
cplusplus11.Examples/UNIX/pthread/pthread-cond.cpp
Source: cplusplus11.Examples/UNIX/pthread/pthread-cond.cpp
/* Adapted from "the Linux Programming Interface"
   Listing 30-4 on Page 649-651
*/

#include<iostream>
#include<unistd.h>
#include<pthread.h>
#include<memory>
#include<string>
#include<ctime>
#include<sys/time.h>
#include<cstdlib>


void error(const std::string &s);

pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t output_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;


int total_threads = 0;
int num_t = 0;
int num_j = 0;

enum STATE { ALIVE, TERM, JOINED };

class ThreadInfo {
public:
    ThreadInfo() : info(nullptr) {
        
    }
    ThreadInfo(unsigned int num) {
        info = new Info[num];
    }
    
    ~ThreadInfo() {
        if(info != nullptr) delete [] info;
    }
    
    void setInfo(unsigned int index, STATE s, pthread_t i, int sl) {
        info[index].state = s ;
        info[index].id = i;
        info[index].sleeptime = sl;
    }
    
    STATE &State(unsigned int index) const { return info[index].state; }
    pthread_t getId(unsigned int index) const { return info[index].id; }
    int getSleep(unsigned int index) const { return info[index].sleeptime; }
private:
    
    struct Info {
        STATE state;
        pthread_t id;
        int sleeptime;
    };
    
    Info *info;
};

std::unique_ptr<ThreadInfo> threads;

void *thread_func(void *arg) {
    long i = (long) arg;
    
    int rt_val;
    sleep(threads->getSleep(i));
    
    rt_val = pthread_mutex_lock(&output_mutex);
    
    if(rt_val != 0)
        error("pthread_mutex_lock");
    
    std::cout << "Thread ID: " << i << " terminating..\n";
    
    rt_val = pthread_mutex_unlock(&output_mutex);
    
    if(rt_val != 0)
        error("pthread_mutex_unlock");
    
    rt_val = pthread_mutex_lock(&mut);
    if(rt_val != 0)
        error("pthread_mutex_lock");
    
    ++num_j;
    
    threads->State(i) = TERM;
    
    rt_val = pthread_mutex_unlock(&mut);
    
    if(rt_val != 0)
        error("pthread_mutex_unlock");
    
    rt_val = pthread_cond_signal(&cond);
    
    if(rt_val != 0)
        error("pthread_mutex_cond");
    
    return 0;
    
}

int main(int argc, char **argv) {
    
    
    if(argc != 2) {
        std::cerr << "Error requires one argument, how many threads..\n" << argv[0] << " numthreads\n";
        exit(EXIT_FAILURE);
    }
    
    int num = atoi(argv[1]);
    if(num <= 0) {
        std::cerr << "Error argument: " << num << "\n";
        exit(EXIT_FAILURE);
    }
    
    total_threads = num;
    threads.reset(new ThreadInfo(num));
    num_t = total_threads;
    num_j = 0;
    
    int rt_val = 0;
    
    for(int i = 0; i < total_threads; ++i) {
        pthread_t id;
        int sleeptime;
        STATE state = ALIVE;
        timeval t;
        gettimeofday(&t, 0);
        srand(time(0)*t.tv_sec*t.tv_usec);
        sleeptime = rand()%5;
        unsigned long index = i;
        rt_val = pthread_create(&id, 0, thread_func, (void*)index);
        if(rt_val != 0)
            error("pthread_create");
        
        threads->setInfo(i, state, id, sleeptime);
    }
    
    while(num_t > 0) {
        rt_val = pthread_mutex_lock(&mut);
        if(rt_val != 0)
            error("pthread_mutex_lock");
        
        while(num_j == 0) {
            rt_val = pthread_cond_wait(&cond, &mut);
            if(rt_val != 0)
                error("pthread_cond_wait");
        }
        
        for(int i = 0; i < total_threads; ++i) {
            if(threads->State(i) == TERM) {
                rt_val = pthread_join(threads->getId(i), 0);
                if(rt_val != 0)
                    error("pthread_join");
                threads->State(i) = JOINED;
                --num_j;
                --num_t;
                
                rt_val = pthread_mutex_lock(&output_mutex);
                
                if(rt_val != 0)
                    error("pthread_mutex_lock");
                
                std::cout << "Claimed thread: " << i << " num alive: "<< num_t << "\n";
                
                rt_val = pthread_mutex_unlock(&output_mutex);
                
                if(rt_val != 0)
                    error("pthread_mutex_unlock");
                
            }
        }
        
        rt_val = pthread_mutex_unlock(&mut);
        if(rt_val != 0)
            error("pthread_mutex_unlock");
    }
    
    return EXIT_SUCCESS;
}

void error(const std::string &s) {
    std::cerr << "Error: " << s << "\n";
    exit(EXIT_FAILURE);
}