First of all, this has to do with homework. Just a little hint would be enough.
What I have to do is to detect when a variable(signal) has changed and announce it in 1 microsecond or less. My progress so far:
int main(int argc, char **argv)
{
int i;
N = atoi(argv[1]);
if (argc != 2) {
printf("Usage: %s N\n"
" where\n"
" N : number of signals to monitor\n"
, argv[0]);
return (1);
}
// set a timed signal to terminate the program
signal(SIGALRM, exitfunc);
alarm(20); // after 20 sec
// Allocate signal, time-stamp arrays and thread handles
signalArray = (int *) malloc(N*sizeof(int));
timeStamp = (struct timeval *) malloc(N*sizeof(struct timeval));
pthread_t sigGen;
pthread_t *sigDet = (pthread_t*) malloc(N * sizeof(pthread_t));
long *signalid = (long*) malloc(N * sizeof(long));
for (i=0; i<N; i++) {
signalArray[i] = 0;
}
for (i = 0; i < N; i++)
{
signalid[i] = (long) i;
pthread_create (&sigDet[i], NULL, ChangeDetector, (void*) signalid[i]);
}
pthread_create (&sigGen, NULL, SensorSignalReader, NULL);
// wait here until the signal
for (i = 0; i < N; i++)
{
pthread_join (sigDet[i], NULL);
}
return 0;
}
void *SensorSignalReader (void *arg)
{
char buffer[30];
struct timeval tv;
time_t curtime;
srand(time(NULL));
while (1) {
int t = rand() % 10 + 1; // wait up to 1 sec in 10ths
usleep(t*100000);
int r = rand() % N;
signalArray[r] ^= 1;
if (signalArray[r]) {
gettimeofday(&tv, NULL);
timeStamp[r] = tv;
curtime = tv.tv_sec;
strftime(buffer,30,"%d-%m-%Y %T.",localtime(&curtime));
printf("Changed %5d at Time %s%ld\n",r,buffer,tv.tv_usec);
}
}
}
void *ChangeDetector (void *arg)
{
char buffer[30];
struct timeval tv;
time_t curtime;
long n = (long) arg;
while (1) {
while (signalArray[n] == 0) {}
pthread_mutex_lock(&mutex);
gettimeofday(&tv, NULL);
curtime = tv.tv_sec;
strftime(buffer,30,"%d-%m-%Y %T.",localtime(&curtime));
printf("Detcted %5ld at Time %s%ld after %ld.%06ld sec\n", n, buffer,tv.tv_usec,
tv.tv_sec - timeStamp[n].tv_sec,
tv.tv_usec - timeStamp[n].tv_usec);
pthread_mutex_unlock(&mutex);
while (signalArray[n] == 1) {}
}
}
With this implementation my program achieves to detect up to 3 signals in time <= 1 us. When more than 3 the response delay up to few ms. How could I detect even more signals in that time? I was wondering how thread tasks are allocated in CPU cores? I've read that it's too painful to manage what is executed on each core by code? Would I earn something with that effort?
Your ChangeDetector() relies on busy-waiting on the flag. The problem is that you can't have more processes simultaneously busy-waiting than you have CPUs - only some subset of your ChangeDetector() processes are actually going to be running at any point in time.
This means that quite often, you have to wait for the right ChangeDetector thread to be scheduled back onto the CPU before it can run and notice that the flag has changed.
If you want to have one ChangeDetector thread for every flag, then you will need to use a non-busy-waiting method, like pthread condition variables (you can have one mutex / condition variable pair per flag). I am not sure if you will be able to get sub-microsecond latency this way, though.
If you want really want to stick with the busy-waiting method, you'll need to limit your number of ChangeDetector threads to less than the number of CPUs, by having each thread responsible for checking multiple array locations in every loop.
Related
I have a question regarding threads in C, I know that to create a thread the function pthread_create is needed and I'm currently working on the dining philosopher problem and in this implementation of that problem I have to look if a philosopher has died of starvation.
I tested my programs and it works well, but to look if a philosopher has died I create another thread that'll always run and check in it if a philosoper has died.
a philosopher will die of starvation if he has not eat during a certain amount of time since his last meal.
Defining the general structure of the program and headers.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/time.h>
struct t_phil;
typedef struct t_info t_info;
typedef struct t_phil t_phil;
typedef struct t_info
{
int num_of_phil;
t_phil *philo;
int min_dinner;
pthread_mutex_t *mutex;
int plate_eaten;
int num_of_dead_phil;
int time_to_die;
int time_to_sleep;
int time_to_eat;
pthread_mutex_t t_mut;
} t_info;
typedef struct t_phil
{
int number;
int has_eaten_all;
int finished_meal;
int is_dead;
t_info *data;
pthread_mutex_t *right;
pthread_mutex_t *left;
struct timeval last_dinner;
pthread_t thread;
} t_phil;
int count = 0;
Here is the function, that'll simulate the dinner, this one works as intended but I am open to possible error or improvement.
void *routine(void *args)
{
t_phil *philo = (t_phil *)(args);
int i = philo->number;
if ((philo->number % 2))
sleep(1);
gettimeofday(&philo->last_dinner, 0);
while (!philo->is_dead)
{
pthread_mutex_lock(philo->left);
printf("Philosopher : %i has take left fork\n", philo->number + 1);
pthread_mutex_lock(philo->right);
printf("Philosopher : %i has take right fork\n", philo->number + 1);
gettimeofday(&philo->last_dinner, 0);
printf("Philosopher :%i is eating in at %li\n", philo->number + 1, philo->last_dinner.tv_sec * 1000);
pthread_mutex_lock(&philo->data->t_mut);
// if (philo->data->num_of_dead_phil && !philo->data->min_dinner)
// break;
if (philo->is_dead)
break;
gettimeofday(&philo->last_dinner, NULL);
philo->finished_meal++;
if (philo->finished_meal == philo->data->min_dinner)
{
philo->data->plate_eaten++;
philo->has_eaten_all = 1;
}
sleep(philo->data->time_to_eat);
pthread_mutex_unlock(&philo->data->t_mut);
pthread_mutex_unlock(philo->left);
pthread_mutex_unlock(philo->right);
if (philo->has_eaten_all)
break;
printf("Philosopher : %i is now sleeping at %li\n", philo->number + 1, philo->last_dinner.tv_sec * 1000);
sleep(philo->data->time_to_sleep);
printf("Philosopher : %i is now thinking at %li\n", philo->number + 1, philo->last_dinner.tv_sec * 1000);
}
return (NULL);
}
This one function is the one not working as intended, and I don't know why is this happening right now, as my if statement seems to have the right condition but I am never entering in the if statement meaning that condition is never met while it should be.
I tested a lot of value and the same result happen each time
void *watchers_phil(void *args)
{
t_info *data = (t_info *)args;
t_phil *phil = data->philo;
int i = 0;
struct timeval now;
while (1)
{
if (data->plate_eaten == data->num_of_phil)
break;
while (i < data->num_of_phil)
{
if ((phil[i].last_dinner.tv_sec) >= ((phil[i].last_dinner.tv_sec) + (long int)data->time_to_die))
{
gettimeofday(&now, NULL);
printf("Unfortunately Philosopher : %i, is dead because of starvation at %li....", phil[i].number, (now.tv_sec * 1000));
phil[i].is_dead = 1;
}
i++;
}
i = 0;
}
return (NULL);
}
int main(int argc, char *argv[])
{
t_info data;
pthread_t watchers;
memset(&data, 0, sizeof(t_info));
data.num_of_phil = atoi(argv[1]);
data.min_dinner = atoi(argv[2]);
data.time_to_eat = atoi(argv[3]);
data.time_to_die = atoi(argv[4]);
data.time_to_sleep = atoi(argv[5]);
t_phil *philo = malloc(sizeof(t_phil) * data.num_of_phil);
if (!philo)
return (1);
pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t) * data.num_of_phil);
data.mutex = mutex;
if (!mutex)
{
free(philo);
return (1);
}
int i = 0;
while (i < data.num_of_phil)
{
pthread_mutex_init(&data.mutex[i], NULL);
i++;
}
printf("Number : %i\n", data.num_of_phil);
pthread_mutex_init(&data.t_mut, NULL);
i = 0;
while (i < data.num_of_phil)
{
philo[i].number = i;
philo[i].has_eaten_all = 0;
philo[i].data = &data;
philo[i].is_dead = 0;
philo[i].right = &data.mutex[i];
if (i == (data.num_of_phil - 1))
philo[i].left = &data.mutex[0];
else
philo[i].left = &data.mutex[i + 1];
i++;
}
data.philo = philo;
i = 0;
while (i < data.num_of_phil)
{
pthread_create(&data.philo[i].thread, NULL, routine, &data.philo[i]);
i++;
}
pthread_create(&watchers, NULL, watchers_phil, &data);
i = 0;
while (i < data.num_of_phil)
{
pthread_join(data.philo[i].thread, NULL);
i++;
}
pthread_join(watchers, NULL);
printf("Dinner eaten : %i\n", data.plate_eaten);
i = 0;
while (i < data.num_of_phil)
{
pthread_mutex_destroy(&data.mutex[i]);
i++;
}
pthread_mutex_destroy(&data.t_mut);
}
I recommend the following approach:
Have an array containing a timestamp for each philosopher thread.
Each philosopher thread updates its respective timestamp either on beginning or ending eating. To determine its own death it can use this timestamp as well. You could store the eating time or the time when starvation occurs, I personally would rather do the latter as it requires calculating this starvation time just once (and you don't need the eating time anywhere else) while the former would need to do it on every test for starvation.
The monitoring thread iterates over all these timestamps doing the following:
Determine if a thread has starved (current time – just get it once in front of the loop! – being after timestamp stored, if you follow my recommendation above). Flag the thread as starved by some suitable way so that you can ignore it next time.
From non-starved threads remember the minimum value.
After iteration sleep as long until this minimum time will be reached (maybe waking up minimally earlier for better precision). If a philosopher updates the timestamp corresponding to this minimum – never mind, the monitor will wake up in vain, just doing nothing, but that won't hurt apart from consuming a bit of CPU time.
Updating the timestamps: You need to be aware that – unless you can guarantee atomic timestamp update – you need to protect them against race conditions between philosopher threads and monitoring thread.
I see two options for:
One single mutex for the entire array. Easy to implement, but either of the involved threads might block another one (two philosophers, if both trying to update at the same time, a philosopher the monitor or the monitor one or more philosophers). If one thread is preempted right while holding this mutex the blocked one(s) need(s) to wait until this thread is scheduled again.
One mutex for each timestamp. The advantage is that blocking only can occur between the monitor and one single philosopher while all other philosophers can go on as usual. The implementation is more complex, though, and the monitor thread will run its tests a bit slower (you won't notice...) due to having to lock and unlock mutexes again and again (system calls involved, these are rather expensive).
Philosophers should hold the mutex over the entire time between reading the timestamp for checking own starvation until having written the updated starvation time. This assures the philosopher cannot starve right while eating, though in between you should do as little work as possible, especially if you opt for one single mutex (if you cannot avoid, then rather opt for multiple ones).
I am making a raytracer, im trying to use pthread to divide the rendering. i noticed that isnt helping with the speed because the function pthread_join is to slow, if i use a loop to make the 'await' is way faster and works almost every time fine. But i cant use that because the time of rendering changes with the scene.
Is there a way to check if a thread is finished, on a more efficient way. This is the code.
`
int threats(t_file *c) //this function creates the threads
{
int i;
int err;
pthread_t th[THREADS];
i = 0;
printf("1\n");
c->thread = -1;
mlx_clear_window(c->mlx_ptr, c->win_ptr);
while (i < THREADS)
{
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)c);
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
// while (i-- >= 0)
// pthread_join(th[i], 0);
//my await function xd
while (i < 200000000)
i++;
mlx_put_image_to_window(c->mlx_ptr, c->win_ptr, c->img.mlx_img, 0, 0);
c->thread = 0;
return 1;
}
void paint_scene(void *a)
{
int y;
int x;
t_ray ray;
int color;
t_file *c;
c = (t_file *)a;
color = 0;
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
x = 0;
while (x < c->win_width)
{
ray = generate_ray(x, y, *c);
color = get_intersections(&ray, c);
if (c->ligth)
color = shading(&ray, color, c);
my_mlx_pixel_put(&c->img, x, y, color);
x++;
}
//ft_printf("\rLoading%d: %d%%", c->thread, y / (c->win_heigth / 100));
y++;
}
pthread_exit(0);
}
`
You have a concurrency problem here in your thread function:
c->thread++;
y = (c->thread * (c->win_heigth / THREADS));
printf("y:%d,hilo%d\n", y, c->thread);
while (y < (c->thread + 1) * (c->win_heigth / THREADS))
{
....
}
c->thread is shared between all threads, and based on likely thread timings and current face of the moon, I can make an educated guess and say that the first thread is calculating the whole image. When starting up, the first thread might see c->thread == -1, but later (if thread startup is faster than the while loop) other thread increase the value until the first thread sees c->thread == THREADS-1
To fix this, each call to create_thread must pass a pointer to a unique parameter object that holds that threads id. So remove the thread member from t_file. It probably serves no purpose there. And create a type of struct that holds the parameters to the thread function:
struct thread_param
{
unsigned int thread;
file_t *c;
}
You use it like this when starting threads:
struct thread_param params[THREADS];
while (i < THREADS)
{
params[i].thread = i;
params[i].c = c;
err = pthread_create(&th[i], 0, (void *)paint_scene, (void *)&(params[i]));
if (err)
return parse_error("Thread Error: CAN NOT CREATE THREAD");
i++;
}
And you access the data in your thread function:
void paint_scene(void *a)
{
struct thread_param *param = (struct thread_param *)a;
unsigned int thread = param->thread;
t_file *c = param->c;
/*
in the rest of the code you remove `c->thread++`
and replace `c->thread` with `thread`
*/
....
}
If you have atomic data types (C11, #ifndef __STDC_NO_ATOMICS__) then implement a global counter and wait until it hits zero (if decreasing) or the amount of threads (if increasing).
e.g.
#include <stdatomic.h>
atomic_int num_jobs;
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
--num_jobs;
pthread_exit(0);
}
int main()
{
num_jobs = THREADS; // same as your number of threads
create_threads(THREADS); // number of threads = THREADS
while (num_jobs) { // loop while threads running
//sleep for a while
}
join_threads(); // join threads for cleanup
return 0;
}
Otherwise classic lock mechanics,
e.g.
#include <pthread.h>
pthread_spinlock_t lock;
int num_jobs;
// called by main
int numJobs()
{
pthread_spin_lock(&lock);
int res = num_jobs;
pthread_spin_unlock(&lock);
return res;
}
// called by thread_func
void decNumJobs()
{
pthread_spin_lock(&lock);
--num_jobs;
pthread_spin_unlock(&lock);
}
int main()
{
pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
// the other stuff as before
pthread_spin_destroy(&lock);
return 0;
}
Another alternative would be with pthread_cond_wait and pthread_cond_signal (mainly to avoid the sleep in the while loop, continue after receiving the signal and not based on a fixed amount of time).
e.g.
#include <pthread.h>
int num_jobs;
pthread_cond_t cond;
pthread_mutex_t lock;
void decNumJobs()
{
pthread_mutex_lock(&lock);
if (--num_jobs == 0)
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void* thread_func(void*)
{
//the work to do in the thread function
//before exit decrease counter
decNumJobs();
pthread_exit(0);
}
int main()
{
num_jobs = THREADS;
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock);
create_threads(THREADS);
pthread_cond_wait(&cond, &lock);
pthread_mutex_unlock(&lock);
join_threads();
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&lock);
return 0;
}
Note: For the sake of simplicity, there is no error checking nor handling. Reading the documentation of the pthread_* functions (return values, interrupted wait, etc) is strongly advised.
I'm trying to create periodic timer with callback function, it works well. But in main() I've sleep() function and it doesn't work as usually. Instead of sleeping for 10 seconds, it just sleeps for 500 ms, which time is set for timer_settime() function. Is it a bug, or normal behaviour?
volatile sig_atomic_t timer_flag = false;
volatile int total_cnt = 0;
timer_t gTimerid;
void start_timer(void)
{
struct itimerspec value;
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 500000000;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 500000000;
timer_create(CLOCK_REALTIME, NULL, &gTimerid);
timer_settime(gTimerid, 0, &value, NULL);
}
void stop_timer(void)
{
struct itimerspec value;
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 0;
timer_settime(gTimerid, 0, &value, NULL);
}
void timer_callback(int sig)
{
timer_flag = true;
}
static void *count(void *ptr)
{
for(;;) {
if(timer_flag == true) {
timer_flag = false;
printf("%d\n", total_cnt++);
}
usleep(1000);
}
return NULL;
}
int main(void)
{
(void) signal(SIGALRM, timer_callback);
start_timer();
pthread_t thread_cnt;
int thread_num = 1;
pthread_create(&thread_cnt, NULL, count, (void*)&thread_num);
clock_t begin, end;
double time_spent;
struct timeval tv1, tv2;
for(;;) {
printf("Main loop\n");
gettimeofday(&tv1, NULL);
sleep(10);
gettimeofday(&tv2, NULL);
printf ("Total time = %f seconds\n",
(double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
(double) (tv2.tv_sec - tv1.tv_sec));
}
return 0;
}
That's normal (=working as standardized). sleep is an interruptible blocking function.
Here's what POSIX says about it:
If sleep() returns because the requested time has elapsed, the value
returned shall be 0. If sleep() returns due to delivery of a signal,
the return value shall be the "unslept" amount (the requested time
minus the time actually slept) in seconds.
If you want sleep uninterrupted, you need to block signals (or you need to sleep again with the remaining time after the first call is interrupted, but then you'll likely want a higher-resolution sleeping function such as nanosleep or clock_nanosleep).
I'm having trouble with creating and implementing a timer for a multithreaded program. I create 3 threads and they are supposed to wait for 1, 2, and 4 seconds, respectively. However all three threads never stop waiting and the program just sits there indefinitely.
I need 2 of my functions looked at:
CreateAndArmTimer():
-I'm not sure if I'm using sigemptyset and sigaddset correctly. I'm supposed to "Create the signal mask corresponding to the chosen signal_number in timer_signal". I basically looked at the man pages for pthread_sigmask and copied what I found there.
WaitFortimer():
-This function is what is causing my program to not finish. My threads function normally up until this point, and once they call this function they get trapped in it and never exit.
Both functions are located at the bottom of my code. I appreciate any help with this! I can't for the life of me get this to work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <signal.h>
int threadNumber = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
#define NUM_THREADS 3
//used to store the information of each thread
typedef struct{
pthread_t threadID;
int num;
int policy;
struct sched_param param;
long startTime;
long endTime;
int signal_number;
int missed_signal_count;
int timer_Period;
sigset_t timer_signal;
timer_t timer_Id;
}ThreadInfo;
ThreadInfo myThreadInfo[NUM_THREADS];
void *ThreadRunner(void *vargp);
void CreateAndArmTimer(int unsigned period, ThreadInfo* threadInfo);
void WaitForTimer(ThreadInfo* threadInfo);
int sigwait(const sigset_t* set, int* sig);
int timer_create(clockid_t clockid, struct sigevent* sevp, timer_t* timerid);
//main function
int main(void){
sigset_t alarm_sig;
sigemptyset(&alarm_sig);
for(int i = SIGRTMIN; i <= SIGRTMAX; i++)
sigaddset(&alarm_sig, i);
pthread_sigmask(SIG_BLOCK, &alarm_sig, NULL); //*****apply the blocking*****
printf("\nrunning...\n");
int fifoPri = 60;
//create the 3 fifo threads
for(int i=0; i<NUM_THREADS; i++){
myThreadInfo[i].policy = SCHED_FIFO;
myThreadInfo[i].param.sched_priority = fifoPri++;
pthread_create(&myThreadInfo[i].threadID, NULL, ThreadRunner, &myThreadInfo[i]);
}
printf("\n\n");
sleep(1);
//tell all the threads to unlock
pthread_cond_broadcast(&cond);
//join each thread
for(int g = 0; g < NUM_THREADS; g++){
pthread_join(myThreadInfo[g].threadID, NULL);
}
return 0;
}
//the function that runs the threads
void *ThreadRunner(void *vargp){
struct tm *ts;
struct timeval tv;
size_t last;
time_t timestamp = time(NULL);
threadNumber++;
ThreadInfo* currentThread;
currentThread = (ThreadInfo*)vargp;
currentThread->num = threadNumber;
if(currentThread->num == 1){
currentThread->timer_Period = 1000000;
}
else if(currentThread->num == 2){
currentThread->timer_Period = 2000000;
}
else{
currentThread->timer_Period = 4000000;
}
//lock the thread until it's ready to be unlocked
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
//unlocking for all other threads
pthread_mutex_unlock(&mutex);
if(pthread_setschedparam(pthread_self(), currentThread->policy,(const struct sched_param *) &(currentThread->param))){
perror("pthread_setschedparam failed");
pthread_exit(NULL);
}
if(pthread_getschedparam(pthread_self(), ¤tThread->policy,(struct sched_param *) ¤tThread->param)){
perror("pthread_getschedparam failed");
pthread_exit(NULL);
}
//create and arm the timer
printf("thread#[%d] waiting for %d seconds\n", currentThread->num, (currentThread->timer_Period/1000000));
CreateAndArmTimer(currentThread->timer_Period, currentThread);
//set the start time of the timer
gettimeofday(&tv, NULL);
long startTime = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
currentThread->startTime = startTime;
//Wait for the timer
WaitForTimer(currentThread);
//set the end time of the timer
gettimeofday(&tv, NULL);
long endTime = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
currentThread->endTime = endTime;
//do the printing
printf("\nThread[%d] Timer Delta[%lu]us Jitter[]us\n", currentThread->num, endTime-startTime);
pthread_exit(NULL);
}
//used to create and arm a new timer
void CreateAndArmTimer(int unsigned period, ThreadInfo* threadInfo){
//Create a static int variable to keep track of the next available signal number
pthread_mutex_lock(&mutex);
static int nextSignalNumber = 0;
if(nextSignalNumber == 0){
nextSignalNumber = SIGRTMIN;
}
else{
nextSignalNumber += 1;
}
pthread_mutex_unlock(&mutex);
threadInfo->signal_number = nextSignalNumber;
//Create the signal mask corresponding to the chosen signal_number in "timer_signal"
//Use "sigemptyset" and "sigaddset" for this
sigemptyset(&threadInfo->timer_signal);
sigaddset(&threadInfo->timer_signal, SIGQUIT);
sigaddset(&threadInfo->timer_signal, SIGUSR1);
//Use timer_Create to create a timer
struct sigevent mySignalEvent;
mySignalEvent.sigev_notify = SIGEV_SIGNAL;
mySignalEvent.sigev_signo = threadInfo->signal_number;
mySignalEvent.sigev_value.sival_ptr = (void*)&(threadInfo->timer_Id);
int ret = timer_create(CLOCK_MONOTONIC, &mySignalEvent, &threadInfo->timer_Id);
if(ret != 0){
printf("error during timer_create for thread#[%d]\n", threadInfo->num);
}
//Arm timer
struct itimerspec timerSpec;
int seconds = period/1000000;
long nanoseconds = (period - (seconds * 1000000)) * 1000;
timerSpec.it_interval.tv_sec = seconds;
timerSpec.it_interval.tv_nsec = nanoseconds;
timerSpec.it_value.tv_sec = seconds;
timerSpec.it_value.tv_nsec = nanoseconds;
int ret2 = timer_settime(threadInfo->timer_Id, 0, &timerSpec, NULL);
if(ret2 != 0){
printf("error with timer_settime!\n");
}
}
//used to make a thread wait for a timer
void WaitForTimer(ThreadInfo* threadInfo){
pthread_sigmask(SIG_UNBLOCK, &threadInfo->timer_signal, NULL); //*****unblock the signal*****
//Use sigwait function to wait on the "timer_signal"
int wait = sigwait(&threadInfo->timer_signal, &threadInfo->signal_number);
if(wait != 0){
printf("error with sigwait!\n");
}
//update missed_signal_count by calling "timer_getoverrun"
threadInfo->missed_signal_count = timer_getoverrun(threadInfo->timer_Id);
}
When I run this, the output is:
running...
thread#[l] waiting for 1 seconds
thread#[2] waiting for 2 seconds
thread#[3] waiting for 4 seconds
First, you should probably be using pthread_sigmask(2) rather than sigprocmask(2). Besides the fact that your comments (instructions, if this is homework?) state that is to be used, the former is explicitly specified as part of the POSIX standard in multithreaded programs, while the latter is not. I don't think this matters on Linux, but it's probably good practice.
The second, and more important, is that you're not really using the signals correctly. First, you block every signal with the call to sigprocmask(2) in your main function, but then never change that. Inside the CreateAndArmTimer() function, you never actually specify that all signals except your threadInfo->signal_number should be blocked. You instead add SIGQUIT and SIGUSR1 to a sigset, but then never do anything with that set. Did you mean to call pthread_sigmask(2) here? If so, you should be sure to add threadInfo->signal_number to the set too before doing so.
On the "listening" side, you never actually unblock any signals in the WaitForTimer() function (or anywhere else). Even if you correctly blocked them earlier, if you don't unblock them before calling sigwait(2), they'll never be delivered to your threads. So the timer is generating the requested signals, but they're just sitting in the signal queue for your process. You must call pthread_sigmask(SIG_UNBLOCK, ...) somewhere so they can actually be delivered.
In short:
Call pthread_sigmask(2) instead of sigprocmask(2).
Block all signals except your chosen threadInfo->signal_number in the threads.
Unblock those signals before calling sigwait(2).
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