10.rtprogramming Handout
10.rtprogramming Handout
10.rtprogramming Handout
Giuseppe Lipari
http://feanor.sssup.it/~lipari
Scuola Superiore SantAnna Pisa
Outline
1
Timing utilities
Periodic threads
Scheduler selection
Exercises
//
//
seconds
nanoseconds
Example
void timespec_add_us(struct timespec *t, long us)
{
t->tv_nsec += us*1000;
if (t->tv_nsec > 1000000000) {
t->tv_nsec = t->tv_nsec - 1000000000;// + ms*1000000;
t->tv_sec += 1;
}
}
int timespec_cmp(struct timespec *a, struct timespec *b)
{
if (a->tv_sec > b->tv_sec) return 1;
else if (a->tv_sec < b->tv_sec) return -1;
else if (a->tv_sec == b->tv_sec) {
if (a->tv_nsec > b->tv_nsec) return 1;
else if (a->tv_nsec == b->tv_nsec) return 0;
else return -1;
}
}
Clocks
clock_id can be:
CLOCK_REALTIME represent the system real-time clock, it
is supported by all implementations. The value of thic clock
can be changed with a call to clock_settime()
CLOCK_MONOTONIC represents the system real-time
since startup, but cannot be changed. Not supported in all
implementations
if _POSIX_THREAD_CPUTIME is defined, then clock_id
can have a value of CLOCK_THREAD_CPUTIME_ID,
which represents a special clock that measures execution
time of the calling thread (i.e. it is increased only when a
thread executes)
if _POSIX_THREAD_CPUTIME it is possible to get a
special clock_id for a specific thread by calling
pthread_getcpuclockid()
#include <pthread.h>
#include <time.h>
int pthread_getcpuclockid(pthread_t thread_id, clockid_t *clock_id);
sleep functions
To suspend a thread, we can call the following functions
#include <unistd.h>
unsigned sleep(unsigned seconds);
#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
Example of usage - I
code/nanosleepexample.c
Example of usage - II
The previous example does not work!
code/nanosleepexample2.c
void *thread(void
{
struct timespec
struct timespec
struct timespec
struct timespec
*arg)
interval;
next;
rem;
now;
interval.tv_sec = 0;
interval.tv_nsec = 500 * 1000000;
clock_gettime(&next);
while(1) {
// perform computation
timespec_add(&next, &interval);
clock_gettime(&now);
timespec_sub(&rem, &next, &now);
nanosleep(&rem, 0);
}
}
// 500 msec
//
//
//
//
Problems
Correct implementation
#include <time.h>
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *rqtp, struct timespec *rmtp);
Example
code/periodicslides.c
struct periodic_data {
int index;
long period_us;
int wcet_sim;
};
void *thread_code(void *arg) {
struct periodic_data *ps = (struct periodic_data *) arg;
int j; int a = 13, b = 17;
struct timespec next;
struct timespec now;
clock_gettime(CLOCK_REALTIME, &next);
while (1) {
timespec_add_us(&next, ps->period_us);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME,
&next, NULL);
for (j=0; j<ps->wcet_sim; j++) a *= b;
}
return NULL;
}
Scheduling policy
Scheduling in POSIX
The scheduling policies in POSIX:
100
99
REALTIME
PRIORITIES
98
(SCHED_FIFO
OR SCHED_RR)
1
0
NON REALTIME
PRIORITIES
(SCHED_OTHER)
39
Example
Warning
Other API
Mutex generalities
Advantages:
It is possible to define RT protocols for scheduling, priority
inheritance, and blocking time reduction
Less possibility for errors
Example continued
code/mutex.c
int main()
{
pthread_t t1,t2,t3;
pthread_attr_t myattr;
int err;
pthread_mutexattr_t mymutexattr;
pthread_mutexattr_init(&mymutexattr);
pthread_mutex_init(&mymutex, &mymutexattr);
pthread_mutexattr_destroy(&mymutexattr);
pthread_attr_init(&myattr);
err = pthread_create(&t1, &myattr, body, (void *)".");
err = pthread_create(&t2, &myattr, body, (void *)"#");
err = pthread_create(&t3, &myattr, body, (void *)"o");
pthread_attr_destroy(&myattr);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
printf("\n");
return 0;
}
Condition variables
To simplify the implementation of critical section with
mutex, it is possible to use condition variables
A condition variable is a special kind of synchronization
primitive that can only be used together with a mutex
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
Condition variables
More on conditions
class SynchObj {
pthread_mutex_t m;
pthread_cond_t c;
int nblocked;
int nthreads;
public:
SynchObj(int n);
void synch();
};
SynchObj::SynchObj(int n)
{
nthreads = n;
nblocked = 0;
pthread_mutex_init(&m, 0);
pthread_cond_init(&c, 0);
}
Example continued
code/synch.cpp
void SynchObj::synch()
{
pthread_mutex_lock(&m);
nblocked++;
if (nblocked < nthreads)
pthread_cond_wait(&c, &m);
else {
nblocked = 0;
pthread_cond_broadcast(&c);
}
pthread_mutex_unlock(&m);
}
Exercise
Implementation
code/synchperiodic.cpp
#include "synchperiodic.h"
PeriodicBarrier::PeriodicBarrier(int n) :
nthreads(n), blocked(0)
{
pthread_mutex_init(&m, 0);
pthread_cond_init(&c_threads, 0);
pthread_cond_init(&c_manager, 0);
}
void PeriodicBarrier::wait(struct timespec *a)
{
pthread_mutex_lock(&m);
blocked++;
if (blocked == nthreads)
pthread_cond_signal(&c_manager);
pthread_cond_wait(&c_threads, &m);
*a = arrival;
pthread_mutex_unlock(&m);
}
void PeriodicBarrier::start()
{
pthread_mutex_lock(&m);
if (blocked < nthreads)
pthread_cond_wait(&c_manager, &m);
pthread_cond_broadcast(&c_threads);
clock_gettime(CLOCK_REALTIME, &arrival);
pthread_mutex_unlock(&m);
}
Thread code
code/exsynchper.cpp
#define NTHREADS 3
PeriodicBarrier pb(NTHREADS);
void *thread_code(void *arg) {
struct periodic_data *ps = (struct periodic_data *) arg;
struct timespec next;
pb.wait(&next);
while (1) {
fprintf(stdout, "TH %d activated at time %ld\n", ps->index,
next.tv_nsec/1000);
waste(ps->wcet_sim);
timespec_add_us(&next, ps->period_us);
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME,
&next, NULL);
}
return NULL;
}
Exercise
Priority Ceiling
Some exercise
1