This text discusses synchronization in multi-threaded programming, specifically focusing on synchronization using mutexes and semaphores. In multi-threaded
Question:
This text discusses synchronization in multi-threaded programming, specifically focusing on synchronization using mutexes and semaphores.
In multi-threaded applications, it is common for multiple threads to work on the same data or exchange results with each other. To prevent inconsistent data, synchronization mechanisms are used to ensure that operations on shared data are completed before it is reused. The critical section, where inconsistencies can occur, is often protected using mutexes, which are mutual exclusion mechanisms.
The pthreads library provides mutex implementation for thread synchronization. Mutexes are binary synchronization mechanisms that can be in either a locked or unlocked state. They can be statically or dynamically initialized. The pthreads library provides three functions for locking and unlocking mutexes: `pthread_mutex_lock`, `pthread_mutex_trylock`, and `pthread_mutex_unlock`. The `pthread_mutex_lock` function blocks until the mutex is available, `pthread_mutex_trylock` attempts to acquire the mutex without blocking, and `pthread_mutex_unlock` releases the mutex.
Static mutexes are created by initializing a global or static variable of type `pthread_mutex_t` using the `PTHREAD_MUTEX_INITIALIZER` constant. They are valid throughout the lifetime of the application and do not need to be managed by the user.
Dynamic mutexes can be created and destroyed during runtime using the `pthread_mutex_init` and `pthread_mutex_destroy` functions, respectively. Additional attributes can be passed to these functions if the default settings are not sufficient or if specific requirements need to be met.
Mutex attributes can be used to configure the behavior of mutexes in different situations. Attributes can be initialized and destroyed using the `pthread_mutexattr_init` and `pthread_mutexattr_destroy` functions. For example, the `pthread_mutexattr_setpshared` function can be used to set the scope of a mutex to process-shared or process-private. The `pthread_mutexattr_settype` function can be used to change the type of a mutex, allowing for different behaviors when a thread tries to lock a mutex multiple times.
In addition to mutexes, semaphores can also be used for thread synchronization. Semaphores are counting structures that can hold values other than just locked or unlocked. They allow a specified number of threads to enter a critical section based on the program flow. POSIX semaphores are defined in the `semaphore.h` header file and come in two forms: named semaphores and unnamed semaphores.
Unnamed semaphores, also known as memory-based semaphores, create their internal information in a shared memory area that can be accessed by multiple threads or processes. They can be created and destroyed using the `sem_init` and `sem_destroy` functions.
Named semaphores are identified by a name and can be used for inter-process communication. They are created and accessed using functions such as `sem_open` and `sem_close`.
Overall, mutexes and semaphores provide synchronization mechanisms for multi-threaded programming, ensuring the integrity of shared data and controlling access to critical sections of code.
Synchronisierung
Exercise
The following exercise task exemplifies the problem that arises from unsynchronized access to a shared resource. In addition, ways to secure the access using the methods introduced earlier should be found.
Primitive Implementation
Two individual functions will serve as example functions that perform operations on a shared global variable. The first function increments a previously defined global variable by a predefined number of iterations passed as an argument. The second function is almost identical, but it decrements the variable.
As an upper limit for the iterations, you can take, for example, the following value, where you can observe the effects:
const size_t MAX_CNT = 10000000;
Start both functions with at least one thread each to increment and decrement the global variable in parallel.
Before starting the threads, initialize the global variable to zero. After successful completion of the counting threads, check the value of the global variable.
What do you notice during the check? Does the value remain the same when running the application repeatedly?
Protecting the Critical Section
Correct the primitive implementation by securing the minimal necessary section using the synchronization mechanisms discussed earlier. As an exercise, implement both the semaphore and mutex variants. To familiarize yourself with handling static and dynamic mutexes, implement both variants here.
Prime Numbers Extension
Since the exercise task does not perform any actual calculations with the values from the critical section, the overhead caused by the security methods is multiple times greater and is not useful in real-world applications in such cases.
To obtain a real advantage from using semaphores, you can refer back to the task from the previous exercise (Operating Systems - Threads). Extend the exercise once again and determine, based on a global variable, which prime numbers each thread should calculate next.
Calculate the speedup factor again and compare it with the previous results.
Results and Approval
To receive approval for the test, the following results must be presented or the following questions must be answered:
1. Explain the different results obtained from multiple executions.
2. What stands out in the implementation with synchronization mechanisms?
3. Calculate the speedup factor for 2 to 16 threads with synchronization mechanisms.
How TO write the results to which file. And calculate SpeedUpFaktor.
Financial Reporting Financial Statement Analysis and Valuation a strategic perspective
ISBN: 978-1337614689
9th edition
Authors: James M. Wahlen, Stephen P. Baginski, Mark Bradshaw