I'm trying to control a process using a timer. (Just trying to see how it works in order to implement it in another program. The purpose of that program is to call a function in a specific interval. But when I did that, it turned out that it was using too much CPU. I'm also trying to avoid using sleep.I got the timer to work, what it was implemented in a while loop, so it was hogging all of the CPU.
What I want is for the timer_handler to unlock the thread so that it can proceed with the rest of the program, and also for it to perform the same exact action at precise intervals.
This is the code that I have so far
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
int set_count = 0;
static int count = 0;
int timer_set();
sem_t sem;
struct inits{
struct sigaction sa;
struct itimerval timer;
}inits[1];
int timer_handler (int signum)
{
printf ("timer expired %d times\n", ++count);
if(sem_post(&sem)== -1){
write(STDERR_FILENO, "sem_post() failed \n", 18);
_exit(EXIT_FAILURE);
return 0;
}
else
return 0;
}
int timer_set(){
memset (&inits[0].sa, 0, sizeof (inits[0].sa));
inits[0].sa.sa_handler = timer_handler;
sigemptyset(&inits[0].sa.sa_mask);
inits[0].sa.sa_flags = 0;
printf("sigaction successfull: \n");
/* Configure the timer to expire after 1000 msec... */
inits[0].timer.it_value.tv_sec = 1;
inits[0].timer.it_value.tv_usec = 0;
/* ... and every 1000 msec after that. */
inits[0].timer.it_interval.tv_sec = 1;
inits[0].timer.it_interval.tv_usec = 0;
/* Start a virtual timer. It counts down whenever this process is
executing. */
if(setitimer (ITIMER_VIRTUAL, &inits[0].timer, NULL) == -1)
handle_error("timer set failed: ");
printf("timerset successful\n");
return 0;
}
int main ()
{
int s = 1;
int j;
int* sval;
printf("S value = %d\n", s);
// scanf("\n%d", &set_count);
if (sem_init(&sem, 1, 1) == -1)
handle_error("sem_init");
else{
printf("sem_init successful\n");
printf("sem_init has been set s = %d\n", s);
}
printf("j = %d\n", j=timer_set());
/* Do busy work. */
while (1)
{
sem_getvalue(&sem, sval);
if (errno==EINVAL)
handle_error("Error returned on sem_getvalue: ");
printf("entered while loop\n, S = %d\n", *sval);
while ((s= sem_wait (&sem))==0 && errno == EINTR)
{
printf("entered while loop, S = %d\n", *sval);
printf("entered sem while loop\n");
continue;
}
if (s == -1)
handle_error("Semaphore Wait failed\n");
else
printf("Semaphore Successful\n");
}
printf("thank you for using this timer. ADIOS!\n");
exit(1);
}
The problem is that it doesn't go through the second loop of while, and freezes.
Sorry I haven't yet figured out how to post proper code, so I apologize if it looks weird. .
Also, I've been researching this for a while now so I apologize if there's something that I have missed in my research which may or may not have answered my question.
Thanks in advance
Related
I have a producer consumer program that reads a file char by char and puts the content inside a buffer.
I need help with outputting the number of rounds the producer function made to deliver characters to the buffer. A round would mean one or more continuous writes to the buffer without being interrupted by wait (due to a full queue).
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
/*
This program provides a possible solution for producer-consumer problem using mutex and semaphore.
I have used 5 producers and 5 consumers to demonstrate the solution. You can always play with these values.
*/
#define MaxItems 5 // Maximum items a producer can produce or a consumer can consume
#define BufferSize 5 // Size of the buffer
sem_t empty;
sem_t full;
int in = 0;
int out = 0;
int buffer[BufferSize];
pthread_mutex_t mutex;
void *producer(void *pno)
{
int item;
for(int i = 0; i < MaxItems; i++) {
item = rand(); // Produce an random item
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = item;
printf("Producer %d: Insert Item %d at %d\n", *((int *)pno),buffer[in],in);
in = (in+1)%BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
void *consumer(void *cno)
{
for(int i = 0; i < MaxItems; i++) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
int item = buffer[out];
printf("Consumer %d: Remove Item %d from %d\n",*((int *)cno),item, out);
out = (out+1)%BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
}
int main()
{
pthread_t pro[5],con[5];
pthread_mutex_init(&mutex, NULL);
sem_init(&empty,0,BufferSize);
sem_init(&full,0,0);
FILE *fp = fopen("file.txt", "r");
if (fp != NULL) {
if (fseek(fp, 0L, SEEK_END) == 0) {
/* Get the size of the file. */
p1.BUFFER_SIZE = ftell(fp);
if (p1.BUFFER_SIZE == -1) { /* Error */ }
/* Allocate our buffer to that size. */
p1.item = malloc(sizeof(char) * (p1.BUFFER_SIZE + 1));
/* Go back to the start of the file. */
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
/* Read the entire file into memory. */
size_t newLen = fread(p1.item, sizeof(char), p1.BUFFER_SIZE, fp);
if ( ferror( fp ) != 0 ) {
fputs("Error reading file", stderr);
} else {
p1.item[newLen++] = '\0'; /* Just to be safe. */
}
}
int a[5] = {1,2,3,4,5}; //Just used for numbering the producer and consumer
for(int i = 0; i < 5; i++) {
pthread_create(&pro[i], NULL, (void *)producer, (void *)&a[i]);
}
for(int i = 0; i < 5; i++) {
pthread_create(&con[i], NULL, (void *)consumer, (void *)&a[i]);
}
for(int i = 0; i < 5; i++) {
pthread_join(pro[i], NULL);
}
for(int i = 0; i < 5; i++) {
pthread_join(con[i], NULL);
}
pthread_mutex_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
In general, there is no way to determine whether the time it takes for a call to sem_wait() to return is extended on account of the semaphore's value initially being zero. The sem_wait() function does not communicate that information.
One thing you could do, however, is to start out with a sem_trywait(), which will fail instead of blocking if it cannot immediately decrement the target semaphore. You could increment a counter in that case, and then proceed to perform a regular sem_wait(). Example:
int full_count = 0;
void *producer(void *pno) {
int my_num = *(int *)pno;
for(int i = 0; i < MaxItems; i++) {
int item = rand(); // Produce an random item
int result = sem_trywait(&empty);
if (result == -1) {
if (errno == EAGAIN) {
full_count += 1;
result = sem_wait(&empty);
// handle any error ...
} else {
// handle other error ...
}
}
pthread_mutex_lock(&mutex);
buffer[in] = item;
printf("Producer %d: Insert Item %d at %d\n", my_num, buffer[in], in);
in = (in + 1) % BufferSize;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
}
Do note that there is no guarantee there that in the event that sem_wait() is called, it will actually block, because the semaphore can be incremented between the trywait and the wait. But it does tell you that if a wait had been performed instead of the trywait, then that wait would have blocked. In that case the producer is indeed delayed on account of a full buffer, even if it doesn't spend any of that delay blocked in sem_wait().
I'm trying to build a lift simulator in which a thread adds lift requests to the buffer and three threads representing lifts take the requests from the buffer and stimulate them simultaneously. I'm using pthread.h and semaphore.h to help me with the multithreaded nature of the program. As the requests need to be served in the order they are produced, I thought it would be best to use a queue as the buffer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <semaphore.h>
#define THREAD_NUM 4
sem_t semEmpty;
sem_t semFull;
pthread_mutex_t mutexBuffer;
pthread_cond_t cond;
pthread_cond_t condII;
// file pointer assignment statements.
FILE *input;
FILE *output;
int count = 0;
int totalRequests = 0;
int totalMovement = 0;
// A structure to store requests.
struct Request
{
int reqNo;
int from;
int to;
};
// A structure to store lift info.
struct Lift
{
int liftNo;
int c_pos;
int movement;
int tMovement;
int tRequests;
};
// Declaring and defining queue functions.
struct queue
{
int size;
int f;
int r;
struct Request *arr;
};
int isEmpty(struct queue *q)
{
if (q->r == q->f)
{
return 1;
}
return 0;
};
int isFull(struct queue *q)
{
if (q->r == q->size - 1)
{
return 1;
}
return 0;
};
void enqueue(struct queue *q, struct Request req)
{
if (isFull(q))
{
printf("This Queue is full\n");
}
else
{
q->r++;
q->arr[q->r] = req;
printf("Enqued element.\n");
}
};
struct Request dequeue(struct queue *q)
{
struct Request r;
if (isEmpty(q))
{
printf("This Queue is empty.\n");
}
else
{
q->f++;
r = q->arr[q->f];
printf("Dequed element.\n");
}
return r;
};
// Declaring Buffer.
struct queue Buffer;
void *request(void *args)
{
struct Request r1;
while (!feof(input))
{
fscanf(input, "%d %d %d", &r1.reqNo, &r1.from, &r1.to);
fprintf(output, "--------------------------------------------\n");
fprintf(output, "Request No: %d\n", r1.reqNo);
fprintf(output, "From Floor %d to Floor %d\n", r1.from, r1.to);
fprintf(output, "--------------------------------------------\n");
while (isFull(&Buffer) == 1)
{
pthread_cond_wait(&condII, NULL);
}
sem_wait(&semEmpty);
pthread_mutex_lock(&mutexBuffer);
enqueue(&Buffer, r1);
count++;
pthread_mutex_unlock(&mutexBuffer);
sem_post(&semFull);
}
}
void *lift(void *args)
{
pthread_mutex_lock(&mutexBuffer);
struct Lift currentLift = *(struct Lift *)args;
struct Request r1;
pthread_mutex_unlock(&mutexBuffer);
while (count > 0)
{
while(isEmpty(&Buffer) == 0){
sem_wait(&semFull);
pthread_mutex_lock(&mutexBuffer);
r1 = dequeue(&Buffer);
count--;
pthread_cond_broadcast(&condII);
currentLift.movement = 0; // Resetting movement.
currentLift.tRequests++; // Incrementing total requests for lift.
totalRequests++; // Incrementing total requests.
fprintf(output, "Lift %d Operations\nPrevious Position: %d Floor\nRequest: number %d from Floor %d to Floor %d\n", currentLift.liftNo, currentLift.c_pos, r1.reqNo, r1.from, r1.to);
fprintf(output, "Detail Operations:\n\tGo from Floor %d to Floor %d\n", currentLift.c_pos, r1.from);
// Stimulating lift movement.
sleep(1);
currentLift.movement += abs(currentLift.c_pos - r1.from);
currentLift.c_pos = r1.from;
fprintf(output, "\tGo from Floor %d to Floor %d\n", r1.from, r1.to);
sleep(1);
currentLift.movement += abs(r1.to - r1.from);
currentLift.c_pos = r1.to;
currentLift.tMovement += currentLift.movement; // Adding to total movement of lift.
fprintf(output, "\t#movement for this request: %d\n", currentLift.movement);
fprintf(output, "\t#Requests: %d\n", currentLift.tRequests);
fprintf(output, "\tTotal #movement: %d\n", currentLift.tMovement);
fprintf(output, "Current Position: %d Floor\n", r1.to);
pthread_mutex_unlock(&mutexBuffer);
sem_post(&semEmpty);
pthread_mutex_lock(&mutexBuffer);
totalMovement += currentLift.tMovement;
pthread_mutex_unlock(&mutexBuffer);
}
}
}
int main(int argc, char *argv[])
{
// Creating thread array, mutexes, semaphores, and lifts.
pthread_t threads[THREAD_NUM];
pthread_mutex_init(&mutexBuffer, NULL);
sem_init(&semEmpty, 0, 5);
sem_init(&semFull, 0, 0);
pthread_cond_init(&cond, NULL);
pthread_cond_init(&condII, NULL);
Buffer.size = 5;
Buffer.f = -1;
Buffer.r = -1;
Buffer.arr = malloc(sizeof(struct Request) * Buffer.size);
struct Lift l1, l2, l3;
// Setting values for lifts.
l1.liftNo = 1;
l2.liftNo = 2;
l3.liftNo = 3;
l1.c_pos = 1;
l2.c_pos = 1;
l3.c_pos = 1;
l1.tMovement = 0;
l2.tMovement = 0;
l3.tMovement = 0;
l1.tRequests = 0;
l2.tRequests = 0;
l3.tRequests = 0;
l1.movement = 0;
l2.movement = 0;
l3.movement = 0;
// Dynamically allocating lifts for use in threads.
struct Lift *lift1 = malloc(sizeof(struct Lift));
*lift1 = l1;
struct Lift *lift2 = malloc(sizeof(struct Lift));
*lift2 = l3;
struct Lift *lift3 = malloc(sizeof(struct Lift));
*lift3 = l2;
// assigning files to file pointers.
input = fopen("sim_input.txt", "r");
if (input == NULL)
{
printf("No file read.\n\n");
return -1;
}
else
{
fseek(input, 0, SEEK_SET);
printf("File read successfully.\n\n");
}
output = fopen("sim_out.txt", "w");
if (output == NULL)
{
printf("No file read.\n\n");
return -1;
}
else
{
printf("File read successfully.\n\n");
}
// Creating producer thread and joining.
if (pthread_create(&threads[0], NULL, &request, NULL) != 0)
{
perror("Failed to create thread");
}
if (pthread_join(threads[0], NULL) != 0)
{
perror("Failed to join thread");
}
// Creating threads and passing lift structures.
if (pthread_create(&threads[1], NULL, &lift, lift1) != 0)
{
perror("Failed to create thread");
}
if (pthread_create(&threads[2], NULL, &lift, lift2) != 0)
{
perror("Failed to create thread");
}
if (pthread_create(&threads[3], NULL, &lift, lift3) != 0)
{
perror("Failed to create thread");
}
// Joining all lifts using loop structure.
for (int i = 1; i < THREAD_NUM; i++)
{
if (pthread_join(threads[i], NULL) != 0)
{
perror("Failed to join thread");
}
}
// Printing total requests and total movements.
fprintf(output, "Total number of requests: %d\n", totalRequests);
fprintf(output, "Total number of movements: %d\n", totalMovement);
// Freeing memory.
if (count < 1)
{
sem_destroy(&semEmpty);
sem_destroy(&semFull);
pthread_cond_destroy(&cond);
pthread_cond_destroy(&condII);
pthread_mutex_destroy(&mutexBuffer);
fclose(input);
fclose(output);
free(lift1);
free(lift2);
free(lift3);
}
return 0;
}
Here's the complete code for the program. It requires sim_input.txt with the following contents:
1 1 5
2 7 2
3 3 8
4 4 11
5 12 15
6 2 9
7 11 7
8 8 15
9 12 19
10 20 7
I assume the program crashes at while(isEmpty(&Buffer) == 0) where I try to fetch the size of the Buffer(Queue) but there might be some other reason too, can you please help?
I assume the program crashes at
You shouldn't assume. Run your program under debugger and observe where it crashes.
Your question lacks MCVE, because your program requires input file sim_input.txt which you didn't provide.
There are obvious bugs though -- you are accessing Buffer from multiple threads, some but not all of these accesses are guarded by a mutex.
For a mutex to be effective, all accesses to variables shared between multiple threads must be guarded, or you will have a data race, which is undefined behavior.
Update:
The actual crash is happening here:
pthread_cond_wait(&condII, NULL);
This call makes absolutely no sense: you must provide a mutex to pthread_cond_wait, and it must be the same mutex as the one used in pthread_cond_signal or similar. Here it should be mutexBuffer, and the code should look something like:
pthread_mutex_lock(&mutexBuffer);
while (isFull(&Buffer)) {
pthread_cond_wait(&condII, &mutexBuffer);
}
// sem_wait() <<- this is bogus/unnecessary
enqueue(&Buffer, r1);
count++;
pthread_mutex_unlock(&mutexBuffer);
There are many other bugs as well, e.g. the code in lift() assumes that it will run after request has been enqueued, and will exit immediately if that hasn't happened.
In my runs, all 3 lift threads exit before a single request is processed.
I'm trying to write a program which creates two threads: a "front-end" and "back-end" thread. I want to create a "back-end" thread to iterate and compute pairs of terms from the fibonacci sequence and put them in an array, and a "front-end" thread that will print out the pairs of the array at each iteration.
"Front-End" Thread - For displaying result of "Back-End" thread operations in each iterations
"Back-End" Thread - For calculating and setting an array
ie. [5, 8], and after an iteration it will contain [13, 21]
I'm struggling to implement the Fibonacci sequence part in a thread and I've made the following progress:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
int fib;
void *front_end(void *ptr);
void *back_end(void *ptr);
int main() {
pthread_t thread1, thread2;
int arr[2] = {5,8};
const int *ptrtoarr;
ptrtoarr=arr;
int create1, create2;
int *s=(int *)(ptrtoarr);
printf("%d \n", *s);
ptrtoarr++;
s = (int *)(ptrtoarr);
printf("%d \n", *s);
ptrtoarr--;
create1 = pthread_create(&thread1, NULL, back_end, &arr);
if(create1) {
fprintf(stderr,"Error - pthread_create() return code: %d\n",create1);
exit(EXIT_FAILURE);
}
pthread_join(thread1, NULL);
//pthread_join(thread2, NULL);
}
// front-end thread to be callback for each back-end iteration
void *front_end(void *ptr) {
int *sum = ptr;
int i, upper = atoi(ptr);
if (upper > 0) {
for (i=0; i<upper; i++){
//Print the fib pairs
}
}
pthread_exit(0);
}
void *back_end(void *ptr) {
int i, upper = atoi(ptr);
fib=1;
if(upper > 0) {
int pre1 = 0;
int current;
//calc fib numbers.....
if(fib == 1){
printf("")
}
}
}
Can someone guide me through how I might approach this?
Your skeleton needs work.
Assuming the following:
unsigned n = ...; // How many to generate.
unsigned n_ready = 2; // How many are ready to print.
unsigned *fibs = malloc(sizeof(unsigned)*n);
fibs[0] = 0;
fibs[1] = 1;
At the core of your back end worker, you will have
for (unsigned i=2; i<n; ++i) {
fibs[i] = fibs[i-2] + fibs[i-1];
n_ready = i+1;
}
At the core of your frontend worker, you will have
for (unsigned i=0; i<n; ++i) {
while (i >= n_ready)
/* Nothing */;
printf("%u\n", fibs[i]);
}
Problem #1
You get into problems if a thread tries to read a variable when another is writing to it. Two or more threads reading the same variable at the same time is ok.
The variables used by both threads are n, the elements of fib[] and n_ready.
n:Not changed by either thread, so we don't need to control access to it.
fib[i] for i >= n_ready:Only accessed by the back end worker, so we don't need to control access to these.
fib[i] for i < n_ready:Only accessed by the frontend worker, so we don't need to control access to these.
n_ready:The back end worker could set n_ready at any time, and the frontend work could try to read n_ready at any time, so we do need to control access to n_ready.
Mutex are usually used to ensure that only one thread is accessing a resource (e.g. a variable, group of variables, file handle, etc) at a time.
Our back end worker becomes
for (unsigned i=2; i<n; ++i) {
// The mutex only protects n_ready
// --nothing else is going to touch fib[i-2] or fib[i-1] or fib[i]--
// so we don't need to obtain a lock yet.
fibs[i] = fibs[i-2] + fibs[i-1];
// We need to access n_ready.
pthread_mutex_lock(&mutex);
n_ready = i+1;
pthread_mutex_unlock(&mutex);
}
Our frontend worker becomes
for (unsigned i=0; i<n; ++i) {
// We need to access n_ready.
pthread_mutex_lock(&mutex);
while (i >= n_ready) {
// Allow other thread to gain the lock.
pthread_mutex_unlock(&mutex);
// We need to access n_ready.
pthread_mutex_lock(&mutex);
}
// The mutex only protects n_ready
// --nothing is going to change fib[i]--
// so we can release it now rather than later.
pthread_mutex_unlock(&mutex);
printf("%u\n", fibs[i]);
}
Problem #2
You have a busy loop. In general, this is bad because it means your thread is using 100% doing nothing by waiting. (In this particular case, since i >= n_ready is probably already true, this would actually be a good strategy. But let's ignore that.) A thread can sleep until signaled by another thread using condition vars.
Our back end worker becomes
for (unsigned i=2; i<n; ++i) {
// The mutex only protects n_ready
// --nothing else is going to touch fib[i-2] or fib[i-1] or fib[i]--
// so we don't need to obtain a lock yet.
fibs[i] = fibs[i-2] + fibs[i-1];
// We need to access n_ready.
pthread_mutex_lock(&mutex);
n_ready = i+1;
// Wake up the other thread if it's blocked.
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
Our frontend worker becomes
for (unsigned i=0; i<n; ++i) {
// We need to access n_ready.
pthread_mutex_lock(&mutex);
while (i >= n_ready)
pthread_cond_wait(&cond, &mutex);
// The mutex only protects n_ready
// --nothing is going to change fib[i]--
// so we can release it now rather than later.
pthread_mutex_unlock(&mutex);
printf("%u\n", fibs[i]);
}
Always call pthread_cond_wait on a locked mutex. It will unlock the mutex when it's called, and it will lock it before returning. This allows the other thread to obtain the mutex in order to change n_ready.
Complete code:
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define UNUSED(x) (void)(x)
// To control access to n_ready.
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static unsigned n_ready = 0; // How many are ready to print.
static unsigned n; // How many to generate.
static unsigned *fibs = NULL;
static void *back_worker(void *unused) {
UNUSED(unused);
fibs[0] = 0;
fibs[1] = 1;
// We need to access n_ready.
pthread_mutex_lock(&mutex);
n_ready = 2;
// Wake up the other thread if it's blocked.
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
for (unsigned i=2; i<n; ++i) {
// The mutex only protects n_ready
// --nothing is going to touch fib[i]--
// so we don't need to obtain a lock yet.
fibs[i] = fibs[i-2] + fibs[i-1];
// We need to access n_ready.
pthread_mutex_lock(&mutex);
n_ready = i+1;
// Wake up the other thread if it's blocked.
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
return NULL;
}
static void *front_worker(void *unused) {
UNUSED(unused);
for (unsigned i=0; i<n; ++i) {
// We need to access n_ready.
pthread_mutex_lock(&mutex);
while (i >= n_ready)
pthread_cond_wait(&cond, &mutex);
// The mutex only protects n_ready
// --nothing is going to change fib[i]--
// so we can release it now rather than later.
pthread_mutex_unlock(&mutex);
printf("%u\n", fibs[i]);
}
return NULL;
}
int main(void) {
n = 20; // How many to generate.
fibs = malloc(sizeof(unsigned) * n);
pthread_t back_thread;
if (errno = pthread_create(&back_thread, NULL, back_worker, NULL)) {
perror(NULL);
exit(1);
}
pthread_t front_thread;
if (errno = pthread_create(&front_thread, NULL, front_worker, NULL)) {
perror(NULL);
exit(1);
}
pthread_join(back_thread, NULL);
pthread_join(front_thread, NULL);
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
free(fibs);
return 0;
}
Output:
$ gcc -Wall -Wextra -pedantic a.c -o a -lpthread && a
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
Suggestion for an exercise to apply the above
Create a pool of workers that print out the numbers placed into a queue. The output doesn't need to be in order.
The worker function is already written for you. You may not change the main or worker functions. I've even created the queue for you. You simply have to make it thread safe by modifying Queue_enqueue, Queue_dequeue and Queue_done functions. These are the only functions you may change.
#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM_WORKERS 4
#define QUEUE_SIZE 10
#define NUM_ITEMS 40
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
int done;
int empty;
int full;
size_t max;
size_t next_insert;
size_t next_read;
unsigned *buf;
} Queue;
static void Queue_init(Queue* q, size_t max) {
pthread_mutex_init(&(q->mutex), NULL);
pthread_cond_init(&(q->cond), NULL);
q->done = 0;
q->empty = 1;
q->full = 0;
q->max = max;
q->next_insert = 0;
q->next_read = 0;
q->buf = malloc(sizeof(unsigned)*max);
}
static void Queue_destroy(Queue *q) {
free(q->buf);
pthread_cond_destroy(&(q->cond));
pthread_mutex_destroy(&(q->mutex));
}
static void Queue_done(Queue *q) {
q->done = 1;
}
// Returns the oldest item from the queue (via a parameter) and returns 1.
// If the queue is empty and done, returns 0.
// If the queue is empty and not done, waits until that changes.
static int Queue_dequeue(Queue *q, unsigned *i) {
while (q->empty && !q->done) {
}
if (q->empty) {
// We are completely done.
return 0;
} else {
*i = q->buf[ q->next_read ];
q->next_read = ( q->next_read + 1 ) % q->max;
q->empty = q->next_read == q->next_insert;
q->full = 0;
return 1;
}
}
// Adds the argument to the queue.
// If the queue is full, waits until that changes.
static void Queue_enqueue(Queue *q, unsigned i) {
while (q->full && !q->done) {
}
if (q->done) {
fprintf(stderr, "Error: Attempted to add item to \"done\" queue.\n");
return;
}
q->buf[q->next_insert] = i;
q->next_insert = ( q->next_insert + 1 ) % q->max;
q->empty = 0;
q->full = q->next_insert == q->next_read;
}
static int msleep(long msec) {
struct timespec ts;
int res;
if (msec < 0) {
errno = EINVAL;
return -1;
}
ts.tv_sec = msec / 1000;
ts.tv_nsec = (msec % 1000) * 1000000;
do {
res = nanosleep(&ts, &ts);
} while (res && errno == EINTR);
return res;
}
// Protects access to stdout.
static pthread_mutex_t stdout_mutex;
static Queue q;
static void *worker(void *worker_id_) {
uintptr_t worker_id = (uintptr_t)worker_id_;
unsigned int seed = worker_id; // Whatever.
unsigned i;
while (Queue_dequeue(&q, &i)) {
pthread_mutex_lock(&stdout_mutex);
printf("[%" PRIuPTR "] Dequeued %u\n", worker_id, i);
pthread_mutex_unlock(&stdout_mutex);
// msleep( rand_r(&seed) % 1000 + 1000 ); // Simulate a 1 to 2s load.
pthread_mutex_lock(&stdout_mutex);
printf("[%" PRIuPTR "] Finished processing %u\n", worker_id, i);
pthread_mutex_unlock(&stdout_mutex);
}
return NULL;
}
int main(void) {
Queue_init(&q, QUEUE_SIZE);
pthread_t workers[NUM_WORKERS];
for (uintptr_t i=0; i<NUM_WORKERS; ++i) {
if (errno = pthread_create(&(workers[i]), NULL, worker, (void*)i)) {
perror(NULL);
exit(1);
}
}
for (unsigned i=0; i<NUM_ITEMS; ++i) {
pthread_mutex_lock(&stdout_mutex);
printf("[x] Enqueuing %u...\n", i);
pthread_mutex_unlock(&stdout_mutex);
Queue_enqueue(&q, i);
pthread_mutex_lock(&stdout_mutex);
printf("[x] Enqueued %u.\n", i);
pthread_mutex_unlock(&stdout_mutex);
}
Queue_done(&q);
pthread_mutex_lock(&stdout_mutex);
printf("[x] Called done.\n");
pthread_mutex_unlock(&stdout_mutex);
for (unsigned i=0; i<NUM_WORKERS; ++i)
pthread_join(workers[i], NULL);
Queue_destroy(&q);
pthread_mutex_destroy(&stdout_mutex);
return 0;
}
If you have questions about this, feel free to post a link to the question as a comment to this answer.
Solution to suggested excercise:
static void Queue_done(Queue *q) {
pthread_mutex_lock(&(q->mutex));
q->done = 1;
pthread_cond_signal(&(q->cond));
pthread_mutex_unlock(&(q->mutex));
}
// Returns the oldest item from the queue (via a parameter) and returns 1.
// If the queue is empty and done, returns 0.
// If the queue is empty and not done, waits until that changes.
static int Queue_dequeue(Queue *q, unsigned *i) {
pthread_mutex_lock(&(q->mutex));
while (q->empty && !q->done)
pthread_cond_wait(&(q->cond), &(q->mutex));
int dequeued;
if (q->empty) {
// We are completely done.
dequeued = 0;
} else {
*i = q->buf[ q->next_read ];
q->next_read = ( q->next_read + 1 ) % q->max;
q->empty = q->next_read == q->next_insert;
q->full = 0;
dequeued = 1;
}
pthread_cond_signal(&(q->cond));
pthread_mutex_unlock(&(q->mutex));
return dequeued;
}
// Adds the argument to the queue.
// If the queue is full, waits until that changes.
static void Queue_enqueue(Queue *q, unsigned i) {
pthread_mutex_lock(&(q->mutex));
while (q->full && !q->done)
pthread_cond_wait(&(q->cond), &(q->mutex));
if (q->done) {
fprintf(stderr, "Error: Attempted to add item to \"done\" queue.\n");
} else {
q->buf[q->next_insert] = i;
q->next_insert = ( q->next_insert + 1 ) % q->max;
q->empty = 0;
q->full = q->next_insert == q->next_read;
}
pthread_cond_signal(&(q->cond));
pthread_mutex_unlock(&(q->mutex));
}
I wrote following code:
void *produce(void* arg)
{
buffer* buff = (buffer *) arg;
while (1)
{
pthread_mutex_lock(&mutex);
if (elements_produced == JOB_SIZE)
{
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
elements_produced++;
while (buff->in_buff == CAPACITY)
{
pthread_cond_wait(&cond_empty, &mutex);
}
// produce
buff->buffer[buff->tail] = rand();
sum_produced += buff->buffer[buff->tail];
printf(">produced %d\n", buff->buffer[buff->tail]);
buff->tail = (buff->tail + 1) % CAPACITY;
buff->in_buff++;
pthread_cond_signal(&cond_empty);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
}
void *consume(void* arg)
{
int rc;
buffer* buff = (buffer *) arg;
while (1)
{
rc = pthread_mutex_lock(&mutex);
if (elements_consumed == JOB_SIZE)
{
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
return 0;
}
elements_consumed++;
while (buff->in_buff == 0)
{
rc = pthread_cond_wait(&cond_empty, &mutex);
}
// consume
printf("<consumed %d\n", buff->buffer[buff->head]);
sum_consumed += buff->buffer[buff->head];
buff->head = (buff->head + 1) % CAPACITY;
buff->in_buff--;
pthread_cond_signal(&cond_full);
pthread_mutex_unlock(&mutex);
}
pthread_exit(NULL);
return 0;
}
All variables are properly initialized. The task is to produce JOB_SIZE elements and to consume them. From time to time it gets stuck in the dead lock. I am quite new to the posix threads so I am probably missing something very obvious (did producers/consumers many times in java/C#/python but now I am really stuck). I know it is much easier to do it with semaphores but I need to do it in this way.
Any suggestions?
You used cond_empty in both sides for the wait. You signal (but never wait on) cond_full.
assume creating 3 worker threads by pthread_create,
in these worker thread routine, each call a simple infinite loop function which do not have a return to do counting
how to make worker thread gain control after calling infinite loop function and save the context of infinite loop function for calling in worker thread again?
Let me rephrase to see if I understood the problem.
You have a master thread which spawns 3 worker threads which each do a long running (infinite) job.
At a certain point you want to interrupt processing, save the state of all threads to resume where they left off at a later time.
I think the best way of doing this is organize your threads work in transactionally bound chunks. When restarting, you check the last completed transaction, and go from there.
But since I suspect this to be a homework assignment in low level thread plumbing, may i suggest a shared boolean which is checked on every time you go through the loop to exit and store the state afterwards. Aternatively "kill" the thread and catch the exception and store the state. The last option is messy.
I think you should clarify your question.
If every worker thread calls an infinite loop then I suppose that your master thread would have to call pthread_cancel() on each of them. From what I gather this might require calls to other pthread_*() functions to set the "cancelability" of the target threads.
Of course this suggestion begs the question. The vastly preferable approach would be to prevent those infinite loops. Write your code so that it has exit conditions ... so that the work is bounded by some sort of input or has some sort of event handling.
want to do the effect of a threadpool, after calling infinite loop function, each worker thread can change other tasks(other infinite loop function) to run
for example 3 worker thread can run 4 tasks(infinite loop functions)
#ifndef JOB_CPP
#define JOB_CPP
#include "job.h"
#define NUM_OF_TASKS 4
#define NUM_OF_WORKERS 3
void (* job_queue[NUM_OF_TASKS])(void*);
void (* fp[NUM_OF_WORKERS])(void*); // original running job
int running_task[NUM_OF_WORKERS];
int idle[NUM_OF_TASKS];
int last_running_task[NUM_OF_WORKERS];
int no_of_tasks_running[NUM_OF_WORKERS];
my_struct_t data = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
void func1(void *arg)
{
int count = 0;
int status;
while(true)
{
//if((count % 100) == 0)
//printf("func1 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func2(void *arg)
{
int count = 0;
int status;
while(true)
{
//printf("func2 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func3(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func3 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.cv);
}
}
void func4(void *arg)
{ int count = 0;
int status;
while(true)
{
//printf("func4 run %d\n", count);
count = count + 1;
//status = pthread_cond_signal(&data.done);
}
}
void jobinit()
{
for(int i=0; i<NUM_OF_TASKS; i++)
{
job_queue[i] = NULL;
idle[i] = 0;
}
for(int i=0; i<NUM_OF_WORKERS; i++)
{
fp[i] = NULL;
running_task[i] = 0;
last_running_task[i] = 0;
no_of_tasks_running[i] = 0;
}
jobadd(func1);
jobadd(func2);
jobadd(func3);
jobadd(func4);
jobrun();
}
void jobadd(void (*job)(void*))
{
for(int i=0; i<4; i++)
{
if(job_queue[i] == NULL)
{
job_queue[i] = job;
return;
}
}
}
void* workserver(void *arg);
void* workserver(void *arg)
{
int status, timedout;
struct timespec timeout;
status = pthread_mutex_lock(&data.mutex);
while(true)
{
timedout = 0;
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_sec += 2;
sleep(1);
//void (* clean)(void*);
status = pthread_cond_timedwait(&data.cv, &data.mutex, &timeout);
if(status == ETIMEDOUT){
printf("worker wait timed out %d\n", (int)arg);
timedout = 1;
}else if(status != 0){
printf("worker wait failed %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
return NULL;
}
printf("workserver number: %d\n", (int)arg);
status = pthread_mutex_unlock(&data.mutex);
printf("function run %d\n", (int)arg);
(* job_queue[(int)arg])(NULL);
printf("cond wait start %d\n", (int)arg);
status = pthread_cond_wait(&data.done, &data.mutex);
printf("cond wait end\n");
status = pthread_mutex_lock(&data.mutex);
}
}
void jobrun()
{
for(int i=0; i<3; i++) {idle[i] = 0;}
pthread_t r1_threadid[3];
for(int i=0; i<3; i++)
{
pthread_create(&r1_threadid[i], NULL, workserver, (void*)i);
}
int status;
struct timespec timeout;
timeout.tv_sec = time (NULL) + 2;
timeout.tv_nsec = 0;
while(true)
{
status = pthread_mutex_lock(&data.mutex);
while(data.value == 0)
{
status = pthread_cond_timedwait(&data.cond, &data.mutex, &timeout);
}
if(data.value != 0)
{
//printf("condition was signaled\n");
data.value = 0;
}
status = pthread_mutex_unlock(&data.mutex);
if(status != 0)
printf("unlock mutex error");
}
}
#endif