Hey, I've got just a small problem related to pthread_cond_timedwait. I've tried implementing it into this piece of code. I can't get the arguments right for timedwait, because I am not too sure what I'm doing. If anyone could point me in the right direction it would be much appreciated!
#include <time.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
pthread_mutex_t timeLock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
int timeIndex = 0;
time_t times[100];
void print_time(time_t tt)
{
char buf[80];
struct tm* st = localtime(&tt);
strftime(buf, 80, "%c", st);
printf("Call me on: ");
printf("%s\n", buf);
}
void *add_time(time_t tt){
if(timeIndex == 100)
timeIndex = 0;
struct timespec ts;
times[timeIndex] = tt;
timeIndex++;
ts.tv_sec = tt;
print_time(tt); // print element
}
void * call_time()
{
while(1)
{
const time_t c_time = time(NULL);
int i;
for(i = 0; i <= 100; i++)
{
if(c_time == times[i])
{
printf("\nWake me up!\n");
times[i] = 0;
}
}
}
}
void * newTime()
{
while(1)
{
time_t f_time;
f_time = time(NULL);
srand ( time(NULL) );
f_time += rand()%100;
add_time(f_time);
sleep(1);
}
}
int main(void)
{
pthread_t timeMet;
pthread_t time;
pthread_create(&time, NULL, newTime, NULL);
pthread_create(&timeMet, NULL, call_time, NULL);
pthread_join(time, NULL);
pthread_join(timeMet, NULL);
return 0;
}
Related
I needed some timer for my program, and I decided to write it with pthreads.
My timer needed to update some info via update callback every update_interval ticks.
I've done it like this:
timer.h:
#include <pthread.h>
enum timer_messages
{
TIMER_START,
TIMER_STOP,
TIMER_PAUSE,
TIMER_EXIT
};
typedef void (*callback)(void *);
struct timer
{
pthread_t thread_id;
struct timeval *interval;
struct timeval *update_interval;
struct timeval *start;
int ls;
int wr;
int enabled;
int exit;
callback update;
callback on_time;
};
struct timer *my_timer_create();
void timer_destroy(struct timer *t);
void timer_set_update_interval(struct timer *t, int seconds, int microseconds);
void timer_set_interval(struct timer *t, int seconds, int microseconds);
void timer_set_update_func(struct timer *t, callback update);
void timer_set_ontime_func(struct timer *t, callback on_time);
void timer_stop(struct timer *t);
void timer_start(struct timer *t);
void timer_exit(struct timer *t);
void timer_pause(struct timer *t);
timer.c:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include "timer.h"
#define TIMEVAL_TO_MICROSECONDS(tv) ((long long)((tv).tv_sec * 1000000 + (tv).tv_usec))
#define GET_TIME_PASSED(start, now) ((TIMEVAL_TO_MICROSECONDS(now) - TIMEVAL_TO_MICROSECONDS(start)))
static int passed(struct timeval *start, struct timeval *interval);
static void fill_timeval(struct timeval *tv, int sec, int microsec);
static void timer_count(struct timer *t);
static void timer_message(struct timer *t);
static void *main_func(void *data);
static void timer_send_msg(struct timer *t, enum timer_messages message);
static struct timeval DEFAULT_TIMEOUT = { 0, 500000 };
static int passed(struct timeval *start, struct timeval *interval)
{
struct timeval cur, sub;
int check;
check = gettimeofday(&cur, NULL);
if(-1 == check)
{
perror("gettimeofday");
return 0;
}
if(GET_TIME_PASSED(*start, cur) < TIMEVAL_TO_MICROSECONDS(*interval))
return 0;
return 1;
}
static void fill_timeval(struct timeval *tv, int sec, int microsec)
{
tv->tv_sec = sec;
tv->tv_usec = microsec;
}
static void timer_count(struct timer *t)
{
int check;
fd_set readfds;
struct timeval timeout;
check = gettimeofday(t->start, NULL);
while(1)
{
if(!t->enabled)
return;
FD_ZERO(&readfds);
FD_SET(t->ls, &readfds);
if(t->update_interval)
memcpy(&timeout, t->update_interval, sizeof(*(t->update_interval)));
else
memcpy(&timeout, &DEFAULT_TIMEOUT, sizeof(DEFAULT_TIMEOUT));
check = select(t->ls + 1, &readfds, NULL, NULL, &timeout);
if(-1 == check)
{
perror("select");
return;
}
if(FD_ISSET(t->ls, &readfds))
timer_message(t);
else
if(t->update)
t->update(t);
if(passed(t->start, t->interval))
{
t->on_time(t);
break;
}
}
}
static void timer_message(struct timer *t)
{
int read_bytes;
char message;
read_bytes = read(t->ls, &message, sizeof(message));
if(-1 == read_bytes)
{
perror("timer_message read");
return;
}
switch(message)
{
case TIMER_START: t->enabled = 1; break;
case TIMER_STOP: t->enabled = 0; t->interval = NULL; t->start = NULL; break;
case TIMER_EXIT: t->enabled = 0; t->exit = 1; break;
case TIMER_PAUSE: break;
default: break;
}
}
static void *main_func(void *data)
{
struct timer *t = data;
fd_set readfds;
int check;
while(!t->exit)
{
if(t->enabled)
{
timer_count(t);
}
else
{
FD_ZERO(&readfds);
FD_SET(t->ls, &readfds);
check = select(t->ls + 1, &readfds, NULL, NULL, NULL);
if(-1 == check)
{
perror("select");
return NULL;
}
if(FD_ISSET(t->ls, &readfds))
timer_message(t);
}
}
return NULL;
}
static void timer_send_msg(struct timer *t, enum timer_messages message)
{
int check;
char msg;
msg = message;
check = write(t->wr, &msg, sizeof(msg));
if(-1 == check)
{
perror("timer_send_msg write");
}
}
struct timer *my_timer_create()
{
int check;
struct timer *t;
int fd[2];
t = malloc(sizeof(*t));
t->interval = malloc(sizeof(*(t->interval)));
t->update_interval = malloc(sizeof(*(t->update_interval)));
t->start = malloc(sizeof(*(t->start)));
check = pipe(fd);
if(-1 == check)
{
perror("pipe");
return NULL;
}
t->ls = fd[0];
t->wr = fd[1];
t->enabled = 0;
t->exit = 0;
t->update = NULL;
t->on_time = NULL;
check = pthread_create(&(t->thread_id), NULL, main_func, t);
if(-1 == check)
{
perror("pthread_create");
return NULL;
}
return t;
}
void timer_destroy(struct timer *t)
{
free(t->interval);
free(t->update_interval);
free(t->start);
close(t->ls);
close(t->wr);
free(t);
}
void timer_set_update_interval(struct timer *t, int seconds, int microseconds)
{
fill_timeval(t->update_interval, seconds, microseconds);
}
void timer_set_interval(struct timer *t, int seconds, int microseconds)
{
fill_timeval(t->interval, seconds, microseconds);
}
void timer_set_update_func(struct timer *t, callback update)
{
t->update = update;
}
void timer_set_ontime_func(struct timer *t, callback on_time)
{
t->on_time = on_time;
}
void timer_stop(struct timer *t)
{
timer_send_msg(t, TIMER_STOP);
}
void timer_start(struct timer *t)
{
timer_send_msg(t, TIMER_START);
}
void timer_exit(struct timer *t)
{
timer_send_msg(t, TIMER_EXIT);
}
void timer_pause(struct timer *t)
{
timer_send_msg(t, TIMER_PAUSE);
}
And then in main file invoked it like this:
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/time.h>
#include "../timer.h"
#define BUF_SIZE 4096
#define TIMEVAL_TO_MICROSECONDS(tv) ((long long)((tv).tv_sec * 1000000 + (tv).tv_usec))
#define GET_TIME_PASSED(start, now) ((TIMEVAL_TO_MICROSECONDS(now) - TIMEVAL_TO_MICROSECONDS(start)))
void progress_bar(int percent, int bar_len)
{
char buf[BUF_SIZE];
int inside = bar_len - 2;
int filled = inside * percent / 100;
int not_filled = inside - filled;
assert(percent <= 100);
assert(bar_len < BUF_SIZE);
buf[0] = '[';
memset(buf + 1, '#', filled);
memset(buf + 1 + filled, '-', not_filled);
buf[bar_len - 1] = ']';
buf[bar_len] = 0;
printf("\r%s %d%%", buf, percent);
fflush(stdout);
}
void timer_ontime(void *data)
{
struct timer *t = data;
puts("");
puts("That's all folks!");
timer_exit(t);
}
void timer_update(void *data)
{
struct timer *t = data;
struct timeval now;
long long passed;
int percent;
gettimeofday(&now, NULL);
passed = GET_TIME_PASSED(*(t->start), now);
percent = passed * 100 / (t->interval->tv_sec * 1000000);
progress_bar(percent, 50);
}
int main(int argc, char **argv)
{
struct timer *t;
int seconds;
int check;
if(argc != 2)
{
fprintf(stderr, "Usage: %s <seconds>\n", argv[0]);
return 1;
}
check = sscanf(argv[1], "%d", &seconds);
if(check != 1)
{
fprintf(stderr, "Couldn't parse number of seconds\n");
return 1;
}
t = my_timer_create();
if(t == NULL)
{
fprintf(stderr, "Couldn't create timer\n");
return 1;
}
timer_set_interval(t, seconds, 0);
timer_set_ontime_func(t, timer_ontime);
timer_set_update_func(t, timer_update);
timer_start(t);
printf("Started timer(%d seconds)\n", seconds);
pthread_join(t->thread_id, NULL);
}
Then i run it with:
[udalny#bulba test]$ time ./timer_check 3
Started timer(3 seconds)
[###############################################-] 99%
That's all folks!
./timer_check 3 0.48s user 1.22s system 56% cpu 3.002 total
So as you can see it takes 56% CPU time. Why so much?
It updates only twice per second(DEFAULT_CALLBACK is 500000 microseconds). And all
other time it is sleeping.
How could I change it so it takes less?
Also I would appreciate any tips on the code.
Your program spends most of its time in timer_count, looping busily - if you add a simple printf before your select:
printf("?\n");
check = select(t->ls + 1, &readfds, NULL, NULL, &timeout);
and run ./timer_check 3 | wc -l you should get millions of lines - meaning the CPU hard-loops on this loop. This is because of the way you initialize your timeout:
if(t->update_interval)
memcpy(&timeout, t->update_interval, sizeof(*(t->update_interval)));
this actually sets your timeout to zero - because you never initialized your t->update_interval in main. This effectively turns your loop into a busy loop.
Add the following line to your main function to fix this:
timer_set_update_interval(t, seconds, 0);
after which you get your desired behavior:
Started timer(3 seconds)
[################################################] 100%
That's all folks!
0.00user 0.00system 0:03.00elapsed 0%CPU (0avgtext+0avgdata 1932maxresident)k
0inputs+0outputs (0major+77minor)pagefaults 0swaps
I m trying to set the flag variable on(working with raspbery pi. I need pin on) for 500 useconds(micro seconds) and flag off for 300 useconds continuously(infinitely until I stop it). I thought of implementing it using 2 timers.
Now In this program i have written for 5 seconds and 3 seconds.
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
struct sigaction sa;
struct itimerval timer1,timer2;
int count=1;
void timer_handler (int signum)
{
if(count++%2==1)
printf("High\n"); //flag=1
else
printf("Low\n"); //flag=0
}
int main ()
{
/* Install timer_handler as the signal handler for SIGVTALRM. */
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timer_handler;
sa.sa_flags = SA_RESTART;
sigaction (SIGALRM, &sa, NULL);
int i=0;
while(1){
scanf(" %d",&i);
if(i==1){ // I m starting 2 timers here
timer1.it_value.tv_sec = 0;
timer1.it_value.tv_usec = 1;
timer1.it_interval.tv_sec = 8; //5+3
timer1.it_interval.tv_usec = 0;
timer2.it_value.tv_sec = 5;
timer2.it_value.tv_usec = 0;
timer2.it_interval.tv_sec = 8;
timer2.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer1, NULL);
setitimer (ITIMER_REAL, &timer2, NULL);
}
else if(i==2) // I m stopping here
{
timer1.it_value.tv_sec = 0;
timer1.it_value.tv_usec = 0;
timer1.it_interval.tv_sec = 0;
timer1.it_interval.tv_usec = 0;
timer2.it_value.tv_sec = 0;
timer2.it_value.tv_usec = 0;
timer2.it_interval.tv_sec = 0;
timer2.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer1, NULL); // 1st timer on
setitimer (ITIMER_REAL, &timer2, NULL); //2nd timer on
}
}
}
This is code I have written.
what actually happening is the second timer is running and first timer is not running. I think its overwritten.
Ps. I dont want to use sleep function as it takes more time. I m using timers as the resolution is microsecond.
1.How do I do this using two timers?
2.Is there any better method to do this task?
There is only one ITIMER_REAL, so you must create virtual timers yourself. A simple and reliable possibility if you don't need microsecond precision, is to use a periodic timer with a small interval and implement your virtual timers on top of that (so every "tick" from your periodic timer will decrement your virtual timers).
Following an example how you could implement it:
vtimer.h
#ifndef VTIMER_H
#define VTIMER_H
typedef void (vtimer_timeout)(void *arg);
typedef struct vtimer
{
int msec;
int periodic;
int current;
vtimer_timeout *timeout;
} vtimer;
#define vtimer_init(m, p, cb) { \
.msec=(m), .periodic=(p), .current=0, .timeout=cb}
void vtimer_start(vtimer *self, void *timeoutArg);
void vtimer_stop(vtimer *self);
// call this periodically, e.g. after each interrupted library call:
void vtimer_dispatch();
#endif
vtimer.c
#define _POSIX_C_SOURCE 200101L
#include "vtimer.h"
#include <stddef.h>
#include <signal.h>
#include <sys/time.h>
#define NUM_TIMERS 8
static vtimer *timers[NUM_TIMERS] = {0};
static void *timoutArgs[NUM_TIMERS] = {0};
static size_t ntimers = 0;
static volatile sig_atomic_t ticks = 0;
static void tickhandler(int signum)
{
(void)signum;
++ticks;
}
static struct sigaction timerAction = {.sa_handler = tickhandler};
static struct sigaction defaultAction;
static struct itimerval tickTimerval = {{0, 1000}, {0, 1000}};
static struct itimerval disableTimerval = {{0,0},{0,0}};
void vtimer_start(vtimer *self, void *timeoutArg)
{
int found = 0;
for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
{
if (timers[idx] == self)
{
found = 1;
break;
}
}
if (!found)
{
if (ntimers == NUM_TIMERS) return; // or maybe return error
if (!ntimers++)
{
// only start the "ticking" timer when necessary
sigaction(SIGALRM, &timerAction, &defaultAction);
setitimer(ITIMER_REAL, &tickTimerval, 0);
}
for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
{
if (!timers[idx])
{
timers[idx] = self;
timoutArgs[idx] = timeoutArg;
break;
}
}
}
self->current = self->msec;
}
void vtimer_stop(vtimer *self)
{
int found = 0;
for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
{
if (timers[idx] == self)
{
timers[idx] = 0;
found = 1;
break;
}
}
if (found && !--ntimers)
{
// no virtual timers running -> stop ticking timer
setitimer(ITIMER_REAL, &disableTimerval, 0);
sigaction(SIGALRM, &defaultAction, 0);
}
}
void vtimer_dispatch(void)
{
while (ticks)
{
--ticks;
for (size_t idx = 0; idx < NUM_TIMERS; ++idx)
{
if (timers[idx])
{
if (!--(timers[idx]->current))
{
timers[idx]->timeout(timoutArgs[idx]);
if (timers[idx]->periodic)
{
timers[idx]->current = timers[idx]->msec;
}
else vtimer_stop(timers[idx]);
}
}
}
}
}
Example program using this:
#include "vtimer.h"
#include <stdio.h>
#include <errno.h>
static void timer1_timeout(void *arg)
{
(void) arg;
puts("timer 1");
}
static void timer2_timeout(void *arg)
{
(void) arg;
puts("timer 2");
}
int main(void)
{
vtimer timer1 = vtimer_init(5000, 1, timer1_timeout);
vtimer timer2 = vtimer_init(8000, 1, timer2_timeout);
vtimer_start(&timer1, 0);
vtimer_start(&timer2, 0);
for (;;)
{
errno = 0;
int c = getchar();
if (c == EOF && errno != EINTR) break;
if (c == 'q') break;
vtimer_dispatch();
}
vtimer_stop(&timer2);
vtimer_stop(&timer1);
return 0;
}
There are a lot of design decisions on the way (e.g. how frequent your ticks should be (here 1ms), having a fixed number of virtual timers vs a dynamic one, using pointers as "timer handles" or maybe integers, and so on), so think about what you need and try to write your own.
so im trying to get this program with semaphores to work.
finally got rid of all of the errors, and now its giving me a core dump issue?
trying to figure out what im doing wrong, been working this all morning and cant seem to find the issue.
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFF_SIZE 20
char buffer[BUFF_SIZE];
int nextIn = 0;
int nextOut = 0;
//char sem_name1[] = "mutex";
//char sem_name2[] = "empty_slots";
//char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
void Put(char item){
sem_wait(empty_slots);
sem_wait(mutex);
buffer[nextIn] = item;
nextIn = (nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ...\n", item);
sem_post(full_slots);
}
void * Producer(){
int i;
for(i = 0; i < 15; i++){
sleep(rand()%6);
Put((char)('A'+ i % 26));
}
}
void Get(char item){
sem_wait(full_slots);
sem_wait(mutex);
item= buffer[nextOut];
nextOut = (nextOut + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Consuming %c ...\n", item);
sem_post(empty_slots);
}
void * Consumer(){
int i;
char item;
for(i = 0; i < 15; i++){
sleep(rand()%6);
Get(item);
}
}
void main(){
sem_init(empty_slots, 0, 1);
sem_init(full_slots, 0, BUFF_SIZE);
sem_init(mutex, 0, 1);
/* Initialize semaphores */
pthread_t pid, cid;
pthread_create(&pid, NULL, Producer, NULL);
pthread_create(&cid, NULL, Consumer, NULL);
// create more consumer & producer threads.
pthread_join(pid, NULL);
pthread_join(cid, NULL);
}
when i use gdb i get the error
(gdb)
Id Target Id Frame
* 1 Thread 0xb7de8700 (LWP 3567) "labp2" __new_sem_init (sem=0x0, pshared=0, value=1)
at sem_init.c:60
(gdb)
Trying to use a bounded buffer from a separate file that I've coded and it seems like that's where the code goes all crazy. Fairly new to C, and I was wondering if I am using the buffer the right way. The concept of instantiation isn't here, so if I just call one of the functions such as bbuff_blocking_insert will the array get initialized? How do I make the appropriate calls in order to get this working?
candy.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "bbuff.h"
#include <stdbool.h>
#include <time.h>
_Bool stop_thread = false;
typedef struct {
int source_thread;
double time_stamp_in_ms;
} candy_t;
double current_time_in_ms (void) {
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
return now.tv_sec * 1000.0 + now.tv_nsec/1000000.0;
}
void* createCandy(void* arg) {
int r;
int factoryNumber = *(int*)arg;
while(!stop_thread) {
r = rand() % 4;
printf("Random Number: %d\n", r);
printf("\tFactory %d ship candy & wait %ds\n", factoryNumber, r);
candy_t *candy = (candy_t*)malloc(sizeof(candy_t));
candy->source_thread = factoryNumber;
candy->time_stamp_in_ms = current_time_in_ms();
bbuff_blocking_insert((void *)candy);
sleep(r);
}
printf("Candy-factory %d done\n", factoryNumber);
return 0;
}
void* extractCandy(void* arg) {
int r;
candy_t* candy;
while(true) {
candy = (candy_t*)bbuff_blocking_extract();
printf("Candy Source Thread: %d\n", candy->source_thread);
r = rand() % 2;
sleep(r);
}
return 0;
}
int main(int argc, char* argv[]) {
//Extract Arguments
if (argc <= 1) {
printf("Insufficient Arguments\n");
exit(-1);
}
int NO_FACTORIES = atoi(argv[1]);
int NO_KIDS = atoi(argv[2]);
int NO_SECONDS = atoi(argv[3]);
bbuff_init();
//Spawn Factory Threads
pthread_t ftids[NO_FACTORIES];
int factoryNumber[NO_FACTORIES];
for (int i = 0; i < NO_FACTORIES; i++) {
factoryNumber[i] = i;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&ftids[i], &attr, createCandy, &factoryNumber[i]);
}
//Spawn Kid Threads
pthread_t ktids [NO_KIDS];
for (int i = 0; i < NO_KIDS; i++) {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&ktids[i], &attr, extractCandy, NULL);
}
//Wait for Requested Time
for (int i = 0; i < NO_SECONDS; i++) {
sleep(1);
printf("Time %ds\n", i+1);
}
//Stop Factory Threads
stop_thread = true;
for (int i = 0; i < NO_FACTORIES; i++) {
pthread_join(ftids[i], NULL);
}
//Wait until no more candy
while(bbuff_is_data_available()) {
printf("Waiting for all candy to be consumed");
sleep(1);
}
//Stop kid Threads
for (int i = 0; i < NO_KIDS; i++) {
pthread_cancel(ktids[i]);
pthread_join(ktids[i], NULL);
}
//Print Statistics
//Clean up any allocated memory
return 0;
}
bbuff.h
#ifndef BBUFF_H
#define BBUFF_H
#define QUEUE_SIZE 10
void bbuff_init(void);
void bbuff_blocking_insert(void* item);
void* bbuff_blocking_extract(void);
_Bool bbuff_is_data_available(void);
#endif
bbuff.c
#include "bbuff.h"
pthread_mutex_t mutex;
sem_t empty;
sem_t full;
int in = 0;
int out = 0;
int counter = 0;
void* buffer[QUEUE_SIZE];
void bbuff_init(void){
pthread_mutex_init(&mutex, NULL);
sem_init( &empty, 0, QUEUE_SIZE);
sem_init( &full, 0, 0);
}
void bbuff_blocking_insert(void* item) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
counter++;
buffer[in] = item;
in = (in+1) % QUEUE_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
void* bbuff_blocking_extract(void) {
void* extractedItem;
sem_wait(&full);
pthread_mutex_lock(&mutex);
counter--;
extractedItem = buffer[out];
buffer[out] = NULL;
out = out % QUEUE_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
return extractedItem;
}
Output
$ ./candykids 1 1 10
Random Number: 3
Factory 0 ship candy & wait 3s
Candy Source Thread: 0
Time 1s
Time 2s
Random Number: 1
Factory 0 ship candy & wait 1s
Time 3s
Segmentation fault (core dumped)
In bbuff_blocking_extract(),
out = out % QUEUE_SIZE;
Should be:
out = (out+1) % QUEUE_SIZE;
Please help the Synchronization
I have to make this program to performe sequentially manner using
in threads( ex) thread1 performe and thread2 perforem and so on)
But it should be implemented only with Semaphore. I put in the wait(), Signal()
function to be act like semaphore(but not working)
You just need to see the pthread_join, and thread_work part
(the main purpose of this program : make 20threads and synchorinize them with semaphore)
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#define num_thread 20
char str[11];
void *thread_work(void *tid); //Main body of Thread working
void generate_str(int n); //Create random character string
void str_sort(void); //Sorting the generated string into alpabet manner
void check_sort(void); //Check about "Is the sorting is right"
void print_time(struct timespec *myclock); //print the time interval of thread work
void print_time_program(struct timespec *myclock);
void wait(void); //I put in these two function to be act like semaphore
void Signal(void); //But it does't work
int S=1;
int main(void)
{
pthread_t tid[num_thread];
int rc;
int t;
struct timespec myclock[4];
srand(time(NULL));
clock_gettime(CLOCK_REALTIME, &myclock[2]);
for(t=0; t<num_thread; t++)
pthread_create(&tid[t], NULL, thread_work, (void *)&t);
for(t=0; t<num_thread; t++)
pthread_join(tid[t], NULL);
clock_gettime(CLOCK_REALTIME, &myclock[3]);
print_time_program(myclock);
return 0;
}
void *thread_work(void *t)
{
do
{
wait(); //Entry Section
//CRITICAL SECTION START
struct timespec myclock[2];
clock_gettime(CLOCK_REALTIME, &myclock[0]);
int n = *((int *)t);
printf("########## Thread #%d starting ########## \n", n);
generate_str(n);
str_sort();
check_sort();
printf("########## Thread #%d exiting ##########\n", n);
clock_gettime(CLOCK_REALTIME, &myclock[1]);
print_time(myclock);
//CRITICAL SECTION END
Signal();
pthread_exit(NULL);
}while (1);
}
void str_sort(void)
{
int temp;
int i, j;
for(i=0; i<9; i++)
for(j=0; j<9-i; j++)
{
if(str[j]>str[j+1])
{
temp=str[j];
str[j]=str[j+1];
str[j+1]=temp;
}
}
printf("Sorted string : %s ", str);
}
void generate_str(int n)
{
int i;
int num;
srand(n);
for(i=0; i<10; i++)
{
num = (97+rand()%26);
str[i]=num;
}
str[10]='\0';
printf("Initialized string : %s \n", str);
}
void check_sort(void)
{
int i;
int count=0;
for(i=0; i<9; i++)
{
if(str[i]>str[i+1])
count++;
}
if(count != 0)
printf("[X] FALSE \n");
else
printf("[O] TRUE \n");
}
void print_time(struct timespec *myclock)
{
long delay, temp, temp_n, sec;
sec = myclock[0].tv_sec % 60;
printf("Thread Starting Time : %ld.%ld second\n", sec, myclock[0].tv_nsec);
sec = myclock[1].tv_sec % 60;
printf("Thread Exiting Time : %ld.%ld second\n", sec, myclock[1].tv_nsec);
if (myclock[1].tv_nsec >= myclock[0].tv_nsec)
{
temp = myclock[1].tv_sec - myclock[0].tv_sec;
temp_n = myclock[1].tv_nsec - myclock[0].tv_nsec;
delay = 1000000000 * temp + temp_n;
}
else
{
temp = myclock[1].tv_sec - myclock[0].tv_sec - 1;
temp_n = 1000000000 + myclock[1].tv_nsec - myclock[0].tv_nsec;
delay = 1000000000 * temp + temp_n;
}
printf("Thread Working Time : %ld nano second", delay);
delay = delay / 1000000;
printf("(%ld ms)\n\n\n", delay);
return ;
}
void print_time_program(struct timespec *myclock)
{
long delay, temp, temp_n, sec;
sec = myclock[2].tv_sec % 60;
printf("Program Starting Time : %ld.%ld second\n", sec, myclock[2].tv_nsec);
sec = myclock[3].tv_sec % 60;
printf("Program Exiting Time : %ld.%ld second\n", sec, myclock[3].tv_nsec);
if (myclock[3].tv_nsec >= myclock[2].tv_nsec)
{
temp = myclock[3].tv_sec - myclock[2].tv_sec;
temp_n = myclock[3].tv_nsec - myclock[2].tv_nsec;
delay = 1000000000 * temp + temp_n;
}
else
{
temp = myclock[3].tv_sec - myclock[2].tv_sec - 1;
temp_n = 1000000000 + myclock[3].tv_nsec - myclock[2].tv_nsec;
delay = 1000000000 * temp + temp_n;
}
printf("Program Total Working Time : %ld nano second", delay);
delay = delay / 1000000;
printf("(%ld ms)\n\n\n", delay);
return ;
}
void wait(void)
{
while( S <= 0);
S--;
}
void Signal(void)
{
S++;
}
Here is a working example of how to make threads execute one after another using a semaphore (Linux/Cygwin pthreads):
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_THREADS 5
/* global thread exit control flag */
volatile uint32_t g_ExitFlag = 0;
/* global thread execution control semaphore */
sem_t g_Sem;
/* the thread function */
void *ThreadFunc(void *pContext)
{
uint32_t tid = (uint32_t)pContext;
/* main thread loop */
while (g_ExitFlag == 0)
{
/* wait for semaphore to be signalled */
sem_wait(&g_Sem);
printf("Thread %d running.\n", tid);
}
printf("Thread %d exiting.\n", tid);
return NULL;
}
int main(int argc, char *argv[])
{
uint32_t i = 0;
pthread_t th;
/* suppress warnings */
(void)argc;
(void)argv;
/* initialize the semaphore */
sem_init(&g_Sem, 0, 0);
/* create and detach several threads */
for (i = 0; i < NUM_THREADS; ++i)
{
pthread_create(&th, NULL, ThreadFunc, (void *)i);
pthread_detach(th);
}
/* run each thread four times and exit */
for (i = 0; i < (NUM_THREADS * 4); ++i)
{
if (i == 15)
{
g_ExitFlag = 1;
}
/* release a thread to execute */
sem_post(&g_Sem);
sleep(1);
}
return 0;
}
It should be straightforward for you to integrate that kind of functionality into your program.