Download presentation
Presentation is loading. Please wait.
Published byLaura Burke Modified over 9 years ago
1
Copyright ©: Nahrstedt, Angrave, Abdelzaher, Caccamo1 Timers and Clocks
2
Copyright ©: Nahrstedt, Angrave, Abdelzaher 2 Example of race condition with signals This example shows what can happen if a signal handler runs in the middle of modifying a variable. struct two_words { int a, b; } memory; void handler(int signum) { printf ("%d,%d\n", memory.a, memory.b); alarm (1); } int main (void) { static struct two_words zeros = { 0, 0 }, ones = { 1, 1 }; signal (SIGALRM, handler); memory = zeros; alarm (1); while (1) { memory = ones; memory = zeros; } This program can print a pair of zeros or a pair of ones. But are we sure these are the only two cases that can happen? The signal function provides a simple interface for establishing an action for a particular signal. Use of this function is unspecified in a multi-threaded process (see man pages!)
3
Copyright ©: Nahrstedt, Angrave, Abdelzaher 3 Example of race condition with signals On most machines, it takes several instructions to store a new value in memory, and the value is stored one word at a time. If the signal is delivered in between these instructions, the handler might find that memory.a is zero and memory.b is one (or vice versa). struct two_words { int a, b; } memory; void handler(int signum) { printf ("%d,%d\n", memory.a, memory.b); alarm (1); } int main (void) { static struct two_words zeros = { 0, 0 }, ones = { 1, 1 }; signal (SIGALRM, handler); memory = zeros; alarm (1); while (1) { memory = zeros; memory = ones; } Note that calling printf in the handler is safe in this program because printf is never called outside the handler when the signal happens
4
Copyright ©: Nahrstedt, Angrave, Abdelzaher 4 POSIX signals and threads In previous lectures, we studied POSIX signals. We assumed that each process had only one single thread of execution. We now need to understand how we can use properly POSIX signals in the presence of multi-threaded applications. We need to be cautious when using threads and signals together, since there are some new subtle rules to remember. We now describe the main aspects of it.
5
Copyright ©: Nahrstedt, Angrave, Abdelzaher 5 Signals & Threads GLOBAL: Signal handler installed by sigaction is global for all the threads. GLOBAL: A signal is delivered only once to any thread (in the process) whose mask is not blocking that particular signal LOCAL: Signal mask is installed on a per thread basis. INHERITANCE: Child threads inherit the mask of parent thread by default. A thread inherits its parent’s mask; but you can change it by using: int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask); Don’t use sigprocmask! That is for PROCESS
6
Copyright ©: Nahrstedt, Angrave, Abdelzaher 6 Signals & Threads Problem: if a signal is sent to a process and more than one thread signalwait for this signal, only one of them get it and the order is random. SOLUTION 1. When a thread is created, it inherits the signal mask of the thread that created it. So if we mask all the signals in main’s thread, no thread will receive any signal after it is created. 2. Dedicate a thread to the purpose of catching signals by using sigwait. This thread will now be in charge of handling the signal. For sigwait to work reliably, we need to follow above solution. That is, the signals being waited for must be masked by all threads. If more than one thread sigwait for the same signal, the signal will be randomly delivered to one of them.
7
Copyright ©: Nahrstedt, Angrave, Abdelzaher 7 Time.h #include time_t time(time_t *tloc); The time() function shall return the value of time in seconds since the Epoch. The tloc argument points to an area where the return value is also stored. If tloc is a null pointer, no value is stored. Epoch: 00:00 (midnight), Jan 1, 1970 GMT time_t is usually a long UNIX “Y2K” Problem: If the long is 32 bits, when will time overflow? Implementations in which time_t is a 32-bit signed integer (many historical implementations) fail in the year 2038.
8
Copyright ©: Nahrstedt, Angrave, Abdelzaher 8 Timing a function (Example 1) #include void function_to_time(void); int main(void) { time_t tstart; tstart = time(NULL); function_to_time(); printf(“function_to_time took %f seconds of elapsed time\n”, difftime(time(NULL), tstart)); return(0); }
9
Copyright ©: Nahrstedt, Angrave, Abdelzaher 9 Time struct tm *localtime(const time_t *timer); Takes time since epoch, returns date char *asctime(const struct tm *timeptr); 26 byte date string in ascii (ex. "Wed Jun 30 21:49:08 1993\n") char *ctime(const time_t *clock); 26 byte date string in ascii (ex. "Wed Jun 30 21:49:08 1993\n") int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst;
10
Copyright ©: Nahrstedt, Angrave, Abdelzaher 10 Gettimeofday() struct timeval time_t tv_sec; /* seconds since the Epoch*/ time_t tv_usec /* and microsoeconds*/ #include int gettimeofday(struct timeval *tv, struct timezone *tz); gives the number of seconds and microseconds since the Epoch Notice that, even though timeval supports microseconds, most operating systems would not support that high resolution since many machines run a 100Hz clock tick tz is null, historical
11
Copyright ©: Nahrstedt, Angrave, Abdelzaher 11 Measure running time using gettimeofday (Example 2) #include #define MILLION 1000000L void function_to_time(void); int main(void) { long timedif; struct timeval tpend; struct timeval tpstart; if (gettimeofday(&tpstart, NULL)) { fprintf(stderr, “Failed to get start time\n”); return 1; }
12
Copyright ©: Nahrstedt, Angrave, Abdelzaher 12 Measure running time using gettimeofday function_to_time(); /* timed code goes here */ if (gettimeofday(&tpend, NULL)) { fprintf(stderr, “Failed to get end time\n”); return 1; } timedif = MILLION*(tpend.tv_sec - tpstart.tv_sec) + tpend.tv_usec – tpstart.tv_usec; printf(“The function_to_time took %ld microseconds\n”, timedif); return 0; }
13
Copyright ©: Nahrstedt, Angrave, Abdelzaher 13 Gettimeofday limitations Expect a resolution on the order of the clock tick of your operating system (1-10 msec) Quiz: What does happen if you have consecutive calls of gettimeofday (within few microseconds)?
14
Copyright ©: Nahrstedt, Angrave, Abdelzaher 14 Gettimeofday limitations Expect a resolution on the order of the clock tick of your operating system (1-10 msec) Quiz: What does happen if you have consecutive calls of gettimeofday (within few microseconds)? It will return the same value!
15
Copyright ©: Nahrstedt, Angrave, Abdelzaher 15 Sleep #include unsigned sleep(unsigned seconds); Returns 0 if successful. Process can be awakened by a SIGNAL (sleep returns unslept time) sleep() may be implemented using SIGALRM; mixing calls to alarm(2) and sleep() is a bad idea.
16
Copyright ©: Nahrstedt, Angrave, Abdelzaher 16 Nanosleep int nanosleep(const struct timespec *req, struct timespec *rem); nanosleep() delays the execution of the program for at least the time specified in *req. The function can return (with error) earlier if a signal has been delivered to the process. In this case, it writes the remaining time into the structure pointed to by rem unless rem is NULL. The structure timespec is used to specify intervals of time with nanosecond precision. It is specified in and has the form struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
17
Copyright ©: Nahrstedt, Angrave, Abdelzaher 17 Nanosleep Compared to sleep(3), nanosleep() has the advantage of having higher resolution, not affecting any signals, and it is standardized by POSIX. nanosleep() is based on the kernel timer mechanism, which has normally a resolution of 1-10 msec (see man 7 time). nanosleep() pauses always for at least the specified time, however it can take up to 10 ms longer than specified until the process becomes runnable again.
18
Copyright ©: Nahrstedt, Angrave, Abdelzaher 18 Elapsed time versus processor time The time function measures elapsed time or wall clock time. The virtual time for a process is the amount of time that the process spends in the running state #include clock_t times(struct tms *buffer); The times() function shall fill the tms structure pointed to by buffer with time-accounting information. The tms structure is defined in. All times are measured in terms of the number of clock ticks used. The tms_utime (of type clock_t) structure member is the CPU time charged for the execution of user instructions of the calling process. The tms_stime (of type clock_t) structure member is the CPU time charged for execution by the system on behalf of the calling process.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.