Created
February 20, 2012 13:15
-
-
Save Alexis-D/1869142 to your computer and use it in GitHub Desktop.
Printer Lab
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
g++ -o printer -std=c++0x -Wall -pedantic -lpthread printer.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iomanip> | |
#include <iostream> | |
#include <pthread.h> | |
#include <queue> | |
#include <semaphore.h> | |
#include <unistd.h> | |
#include <vector> | |
#define NPRINTERS 5 | |
typedef size_t Printer; // a printer just store the number of jobs done | |
typedef size_t Job; // a job is identified by its id (but we don't use it!) | |
std::priority_queue<Printer, std::vector<Printer>, std::greater<Printer>> | |
printers_queue; // use to prioritize the less-used printers | |
sem_t jobs_sem; // used to keep count of jobs | |
pthread_mutex_t printers_mutex, jobs_mutex; // lock printers_queue & | |
// printers_vect, and jobs_queue | |
std::queue<Job> jobs_queue; // hold the queue of jobs | |
std::vector<Printer> printers_vect; // "constant" ref to vectors | |
// we could do without it if "really" | |
// needed... | |
// display the load to the user | |
void* show_progress(void*) { | |
// always show two decimal places | |
std::cout << std::fixed << std::setprecision(2); | |
while(true) { | |
// clear screen && go home (top left) | |
std::cout << "\x1B[2J\x1B[H"; | |
// total number of jobs done | |
int total = 0; | |
pthread_mutex_lock(&printers_mutex); | |
for(auto p : printers_vect) { | |
total += p; | |
} | |
pthread_mutex_unlock(&printers_mutex); | |
// because / 0 otherwise | |
if(total) { | |
size_t idx = 0; | |
for(auto p : printers_vect) { | |
// printer "id" | |
std::cout << "#" << idx << " "; | |
// progress bar | |
double ratio = (double)p / total; | |
size_t width = 50, load = ratio * width, | |
free = width - load; | |
std::cout << "\t["; | |
for(size_t i = 0; i < load; ++i) { | |
std::cout << "#"; | |
} | |
for(size_t i = 0; i < free; ++i) { | |
std::cout << " "; | |
} | |
std::cout << "]"; | |
// percentage | |
std::cout << " " << (ratio * 100.); | |
std::cout << "%\t(" << p << ")\n"; | |
++idx; | |
} | |
std::cout << total << " jobs done so far (avg: "; | |
std::cout << ((double)total / NPRINTERS); | |
std::cout << " jobs/printer)." << std::endl; | |
usleep(500000); | |
} | |
} | |
return NULL; | |
} | |
// add job, sleep, loop | |
void* create_job(void*) { | |
size_t id = 0; | |
while(true) { | |
pthread_mutex_lock(&jobs_mutex); | |
jobs_queue.push(id); | |
pthread_mutex_unlock(&jobs_mutex); | |
sem_post(&jobs_sem); | |
usleep(rand() % 100000); | |
} | |
return NULL; | |
} | |
void* printer_handler(void *arg) { | |
Printer &p = printers_vect[(size_t)arg]; | |
while(true) { | |
// wait new job | |
sem_wait(&jobs_sem); | |
pthread_mutex_lock(&printers_mutex); | |
// if it's my turn | |
if(printers_queue.top() == p) { | |
printers_queue.pop(); // we're busy | |
pthread_mutex_unlock(&printers_mutex); | |
pthread_mutex_lock(&jobs_mutex); | |
jobs_queue.front(); // get the job | |
jobs_queue.pop(); // remove it | |
pthread_mutex_unlock(&jobs_mutex); | |
usleep(rand() % 100000); // print | |
++p; // increase the number of finished jobs | |
pthread_mutex_lock(&printers_mutex); | |
printers_queue.push(p); // we're available | |
pthread_mutex_unlock(&printers_mutex); | |
} | |
else { | |
// resignal the job 'til someone get it | |
// non-deterministic | |
pthread_mutex_unlock(&printers_mutex); | |
sem_post(&jobs_sem); | |
} | |
} | |
return NULL; | |
} | |
int main(int argc, char *argv[]) { | |
sem_init(&jobs_sem, 0, 0); | |
printers_mutex = PTHREAD_MUTEX_INITIALIZER; | |
jobs_mutex = PTHREAD_MUTEX_INITIALIZER; | |
for(size_t i = 0; i < NPRINTERS; ++i) { | |
Printer p = Printer(0); | |
printers_queue.push(p); | |
printers_vect.push_back(p); | |
} | |
pthread_t show, create, printers[NPRINTERS]; | |
pthread_create(&show, NULL, show_progress, NULL); | |
pthread_create(&create, NULL, create_job, NULL); | |
for(size_t i = 0; i < NPRINTERS; ++i) { | |
pthread_create(&printers[i], NULL, printer_handler, (void*)i); | |
} | |
pthread_join(show, NULL); | |
pthread_join(create, NULL); | |
for(size_t i = 0; i < NPRINTERS; ++i) { | |
pthread_join(printers[i], NULL); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment