260 likes | 435 Views
LAB 11: Task Synchronization. Chung-Ta King National Tsing Hua University. CS 4101 Introduction to Embedded Systems. Introduction. In this lab, we will learn To synchronize tasks using synchronization primitives of MQX. Outline. Introduction to task synchronization Events Mutex
E N D
LAB 11: Task Synchronization Chung-Ta King National Tsing Hua University CS 4101 Introduction to Embedded Systems
Introduction • In this lab, we will learn • To synchronize tasks using synchronization primitives of MQX
Outline • Introduction to task synchronization • Events • Mutex • Semaphores
Semaphores Semaphores are used to: Control access to a shared resource(mutual exclusion) Signal the occurrence of an event Allow two tasks to synchronize their activities Basic idea A semaphore is a token that your code acquires in order to continue execution If the semaphore is already in use, the requesting task is suspended until the semaphore is released by its current owner post and wait
How Semaphores Work? A semaphore has: Counter: maximum number of concurrent accesses Queue: for tasks that wait for access If a task waits for a semaphore if counter > 0, counter is decremented by 1, and task gets the semaphore and proceed to do work else task is put in the queue If a task releases (post) a semaphore if there are tasks in the semaphore queue, appropriate task is readied, according to queuing policy Else counter is incremented by 1
Example of Semaphores • The example manages a FIFO queue that multiple tasks can write to and read from. • Mutual exclusion is required for access to the FIFO • Task synchronization is required to block the writing tasks when the FIFO is full, and to block the reading tasks when the FIFO is empty. • Three semaphores are used: • Index semaphore for mutual exclusion on FIFO • Read semaphore to synchronize the readers. • Write semaphore to synchronize the writers. • Three tasks: Main, Read, Write
Example of Semaphores: Main 3: Initial number of semaphores that can be created 1: Number of semaphores to be added when the initial number have been created 6: Max. number of semaphores that can be created
Attributes of Semaphores When a task creates a semaphore, it specifies: Count: initial value for the number of requests that can concurrently have the semaphore Flag: specifying followings Priority queuing: if specified, the queue of tasks waiting for the semaphore is in priority order, and MQX puts the semaphore to the highest-priority waiting task. Otherwise, use FIFO queue. Priority inheritance: if specified and a higher-priority task is waiting, MQX raises priority of the tasks that have the semaphore to that of the waiting task. Strictness: if specified, a task must wait for the semaphore, before it can post the semaphore.
Example of Semaphores: Read FIFO queue is not empty Safe to get data from FIFO
Example of Semaphores: Write Can be entered ARRAY_SIZE times w/o being blocked
Semaphores and RoundRobin: User config.h 1. Add the definition in bsp_twrk60d100m/twrk60d100m/user_config.h 2. Rebuild the bsp and psp library 2 1 2
Tasks and Queues … k writer tasks (read 3-axis data) semaphore (count = n) • States of queue: • Assigned • Filled • Emptied … n queues 1 reader task
Tasks and Queues • Let k > n • At most n of the k writers can access the queues at any time need a semaphore with count = n • Each writer is assigned to write to one queue • Coordination among writers and reader: • Assigned = 1: queue is assigned to a writer task for writing. • Filled = 1: queue is filled with data and is ready for read • Emptied = 1: queue has been read and is ready for write
Solution Strategies Use 3 arrays, Assigned[n], Filled[n], Emptied[n], to track the states of the queues The writer and reader tasks only need to lock the arrays to change the states of the queues. Initially all Assigned[] and Filled[] elements are 0 and Emptied[] elements are 1.
Solution Strategies Writer tasks: Get a semaphore Check the Assigned[] array to find an unassigned queue, lock it, and change Assigned[i] to 1. Wait until Emptied[i] becomes 1. (The queue now should have Filled = 0 and Emptied = 1.) Reset Emptied[i] to 0. Fill the queue. (The queue should be kept at Filled = 0 and Emptied = 0.) When done, set Filled[i] = 1. Release semaphore, reset Assigned[i] to 0.
Solution Strategies Reader task: Check for any Filled[i] = 1. Reset Filled[i] to 0 and read the data. When done, set Emptied[i] = 1.
Basic Lab 1 • There is race condition in the sample code. • Using semaphore to protect the critical data structures with smallest critical section and use RoundRobin.
Basic Lab 2 • There is race condition in the sample code. • Based on basic lab 1. Using Mutex to protect the critical data structures.
Bonus Lab • The code is based on basic lab 1 • In write_task(), after the task grabs a buffer by finding the first buffer with Assigned[i] == 0, it waits for Emptied[i] == 1 using a while-loop. This is basically a spin-wait, which wastes CPU. • Use Events to let the task blocked wait.