Consider the following Barrier method to implement synchronization :
void barrier
{
P(s);
process_arrived++;
V(s);
while(process_arrived != 3);
P(s);
process_left++;
if(process_left == 3)
{
process_Arrived = 0;
process_left = 0;
}
V(s);
}
It is known that this code does not work because of a flaw, but I am not able to find the flaw.
The problem is with the condition : if (process_left == 3)
It may lead to deadlock if two barrier invocations are used in immediate succession.
Initially, process_arrived and process_left will be '0'.
When a process arrives, it increments process_arrived and waits till maximum number of processes have arrived. After that processes are allowed to leave.
Consider the following scenario:
P1 comes and waits till process_arrived becomes 3 ( currently process_arrived = 1)
P2 comes and waits till process_arrived becomes 3 ( currently process_Arrived = 2)
Now P3 comes for execution. The condition in while loop fails and executes further, making process_left = 1 and again enters the function immediately.
It makes process_Arrived = 4 and waits in while loop.
P2 gets a chance to execute makes process_left = 2 and leaves.
P1 executes further and finds that process_left = 3, thereby making both process_arrived and process_left = 0. (Remember that P3 has already entered and is waiting at the barrier, so here a count is lost)
P1 again executes , makes process_arrived = 1 and waits.
P2 also executes again. makes process_arrived = 2 and waits.
Now every process will wait for ever. Hence a deadlock has occurred.
Related
I have a program with 2 timer functions like this (p_maj_input and p_maj_output_motion are equal so the period of both timer is the same):
maj_input = timer('ExecutionMode','fixedRate','Period',p_maj_input,'TasksToExecute', ...
floor(Tmeasurement/p_maj_input)-1,'TimerFcn',{#time_append,p_maj_input,HR_all,freq_HR, ...
BVP_all,freq_BVP,TEMP_all,freq_TEMP,ACC_x_all,ACC_y_all,ACC_z_all,freq_ACC,EDA_all,freq_EDA, ...
folder_all,all_dir,num_dir}); start(maj_input);
maj_output_motion=timer('ExecutionMode','fixedRate','Period',p_maj_output_motion,'TasksToExecute', ...
floor(Tmeasurement/p_maj_output_motion)-1,'TimerFcn',{#output_motion_append, ...
freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir});%,'StartDelay',min(5,p_maj_output_motion)); %startDelay must be min 5 for walk detection start(maj_output_motion);
In each timer callback function there is a loop over subfolders contained in a folder that is selected at the beginning of the program.
output_motion_append(obj,event,freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir)
fprintf('motion %d\n',obj.TasksExecuted)
toc
for folder_index=1:num_dir
[folder_original,folder_fictive] = subfolderFunction(all_dir, folder_all, folder_index);
fileName=strcat(folder_fictive,'\ACC.csv');
[ACC_time, ACC_x, ACC_y, ACC_z] = loadValuesE4_acc(fileName);
% Motion Amount
[agitation,agitation_ts] = identifyAgitation(ACC_x,ACC_y,ACC_z,ACC_time);
agitation=agitation';
len1=length(agitation);
if len1<=freq_MOTION*p_maj_output_motion
i_init1=1;
elseif len1>freq_MOTION*p_maj_output_motion
i_init1=len1-freq_MOTION*p_maj_output_motion+1;
end
writematrix([agitation(i_init1:len1)],strcat(folder_fictive,'\MOTION_output.csv'),'WriteMode','Append');
writematrix([mvt_score(i_init2:len2)],strcat(folder_fictive,'\neurologicScore_output.csv'),'WriteMode','Append');
end
end
Everything works fine if the number of subfolders is lower than 4 : the good values appear in the files on which is carried out the writematrix function. And the timer callback function are are called one after the other, so both timer work simultaneously.
However if there are 5 subfolders or more, it is not the good values and using the debugging I noticed that the first callback function is triggered the number of 'TasksToExecute', and then only the second callback function seems to be called. That is to say the 2 timers don't work simultaneously.
I have tried to increase p_maj_input and p_maj_output_motion to see if the problem is that matlab can't finish to run before another timer callback function is called but still for 5 subfolders I get the same problem.
Does anyone know where my problem is coming from?
This behavior occurs because one timer hasn't finished executing by the time it triggers again, so the second timer never has a chance to execute until the first timer is finished. If you change the ExecutionMode from 'fixedRate' to 'fixedSpacing', then you'll guarantee that there's time for the second timer to execute.
function duelingTimers()
disp('With ExecutionMode = fixedRate')
t1 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn1);
t2 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn2);
cleanup = onCleanup(#()delete([t1,t2]));
function timerFcn1(~,~)
pause(0.2)
disp('Timer 1');
end
function timerFcn2(~,~)
pause(0.2)
disp('Timer 2');
end
start(t1),start(t2)
wait(t1)
wait(t2)
disp(newline)
disp('With ExecutionMode = fixedSpacing')
t1.ExecutionMode = 'fixedSpacing';
t2.ExecutionMode = 'fixedSpacing';
start(t1),start(t2)
wait(t1)
wait(t2)
end
I am using a Queue and hold block together, where the hold remains blocked until all the agents arrive at the Queue block.
How to change it and want to allow only a fixed number of agents (say 5 agents) at fixed intervals of time(say every 3 minutes)? Current properties of my Queue and hold block:
queue_block_properties
hold_block_properties
Create a cyclic event with recurrence time 3 minutes.
Also create a variable which you can name count of type int.
In the event action field write:
count = 0;
hold.unblock();
Then, in the On enter field of the hold block write the following:
count++;
if( count == 5 ) {
self.block();
}
The only question that I have is whether you want every 3 minutes to have exactly 5 agents leave or whether it's okay if they arrive a bit later. In other words if after 3 minutes, there are only 3 agents in the queue, do they leave and the hold remains unblocked in case another 2 arrive before the next cycle? Or does the hold block blocks again immediately?
In the solution I provided, if there are less than 5 at the cycle time occurrence, and then new agents arrive before the next cycle, they can pass.
Otherwise, create a new variable called target for example and write the following in the event action:
count= 0;
if( queue.size() >= 5 ) {
target = 5;
hold.unblock();
}
else if ( queue.size() > 0 ) {
target = queue.size();
hold.unblock();
}
And in the on enter of the hold, write:
count++;
if( count == target ) {
self.block();
target = 0;
}
I would advise to not use a hold block for such delicate control of releasing agents. Instead, I would propose a simpler solution.
Simply let the agents build up in the queue and then you remove them using an event. The only action for this event is to remove the minimum between your set number of agents and the queue size, from the queue and send them to an enter block. The enter block is where your process flow then continues. See the screenshot below.
Code in the event is
for (int i = 0; i < min(5, queue.size()); i ++){
enter.take(queue.remove(0));
}
On that note, you can also use the Wait block (Which is hidden in the Auxillary section in the PML library
Then you can ditch the enter block and simply call the following code
for (int i = 0; i < min(5, wait.size()); i ++){
wait.free(wait.get(0));
}
I am using FreeRTOS to dispatch task set of 4 periodical tasks.
All tasks have the same period of 10 time units, but they differ in their release times. Release times are 10,3,5,0 time units for tasks T1,T2,T3,T4 respectively. All 4 tasks are stored inside the linked list gll_t* pTaskList. Tasks should run e.g.,
t=0 T4 is released, t=3 T2 is released, t=5 T3 is released, t=10 T1 is relased and T4 is executed again since it was released at t = 0, and so on...
However I have two problems with my dispatcher code:
1. Problem At t=0, only T4 is ready, but note that T1 has release time at 10, According to my if statement for T1 I have 0 % (10 + 10) == 0, and T1 gets released even though it's not ready. I could introduce a boolean that tells whether a task has been released, but is there a smarter way to do it without introducing extra variables?
2. Problem At t=26, no tasks are ready, however, task T2 gets released. According to my if statement for T2 I have 26 % (3 + 10) == 0.
void prvTaskSchedulerProcess(void *pvParameters) {
...
uint32_t uCurrentTickCount = 0;
gll_t* pTaskList = (gll_t*) pvParameters;
WorkerTask_t* pWorkerTask = NULL;
while (true) {
for (uint8_t uIndex = 0; uIndex < pTaskList->size; uIndex++) {
pWorkerTask = gll_get(pTaskList, uIndex);
// Check if the task is ready to be executed
if ( (uCurrentTickCount % (pWorkerTask->uReleaseTime + pWorkerTask->uPeriod) ) == 0) ){
// Dispatch the ready task
vTaskResume(pWorkerTask->xHandle);
}
}
uCurrentTickCount++;
// Sleep the scheduler task, so the other tasks can run
vTaskDelay(TASK_SCHEDULER_TICK_TIME * SCHEDULER_OUTPUT_FREQUENCY_MS);
}
}
Using extra flags seems like a simple solution. However I was told that introducing flags variables is not best solution, because it makes code less readable and maintainable. Thus, I want to avoid using them. How would the correct task dispatching be achieved without using the extra flags (possibly correcting my if statement condition)?
Note using vTaskResume() in this way in inherently dangerous if there is even the tiniest little chance that the task you are resuming has not finished its previous actions and suspended itself again. See the API docs for a fuller explanation https://www.freertos.org/taskresumefromisr.html
To fix problem 2, use the following condition instead of what you have.
if ((uCurrentTickCount % pWorkerTask->uPeriod) == pWorkerTask->uReleaseTime)
To fix problem 1 (and problem 2), use the following condition.
if ((uCurrentTickCount >= pWorkerTask->uReleaseTime) &&
((uCurrentTickCount % pWorkerTask->uPeriod) == (pWorkerTask->uReleaseTime % pWorker->uPeriod)))
I have trouble understanding the implementation of a monitor in terms of semaphores from Operating System Concepts
5.8.3 Implementing a Monitor Using Semaphores
We now consider a possible implementation of the monitor mechanism
using semaphores.
For each monitor, a semaphore mutex (initialized to 1) is provided. A
process must execute wait(mutex) before entering the monitor and must
execute signal(mutex) after leaving the monitor.
Since a signaling process must wait until the resumed process either leaves or waits, an additional semaphore, next, is introduced,
initialized to 0. The signaling processes can use next to suspend
themselves. An integer variable next_count is also provided to count
the number of processes suspended on next. Thus, each external
function F is replaced by
wait(mutex);
...
body of F
...
if (next count > 0)
signal(next);
else
signal(mutex);
Mutual exclusion within a monitor is ensured.
We can now describe how condition variables are implemented as well.
For each condition x, we introduce a semaphore x_sem and an
integer variable x_count, both initialized to 0. The operation x.wait() can now be implemented as
x_count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x sem);
x_count--;
The operation x.signal() can be implemented as
if (x_count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
What does the reason for introducing semaphore next and the count next_count of processes suspended on next mean?
Why are x.wait() and x.signal() implemented the way they are?
Thanks.
------- Note -------
WAIT() and SIGNAL() denote calls on monitor methods
wait() and signal() denote calls to semaphore methods, in the explanation that follows.
------- End of Note -------
I think it is easier if you think in terms of a concrete example. But before that let's first try to understand what a monitor is. As explained in the book a monitor is a Abstract Data Type meaning that it is not a real type which can be used to instantiate a variable. Rather it is like a specification with some rules and guidelines based on which different languages could provide support for process synchronization.
Semaphors were introduced as a software-based solution for achieving synchronization over hardware-based approaches like TestAndSet() or Swap(). Even with semaphores, the programmers had to ensure that they invoke the wait() & signal() methods in the right order and correctly. So, an abstract specification called monitors were introduced to encapsulate all these things related to synchronization as one primitive so simply any process executing inside the monitor will ensure that these methods (semaphore wait and signal) invocations are used accordingly.
With monitors all shared variables and functions (that use the shared variables) are put into the monitor structure and when any of these functions are invoked the monitor implementation takes care of ensuring that the shared resources are protected over mutual exclusion and any issues of synchronization.
Now with monitors unlike semaphores or other synchronization techniques we are not dealing with just one portion of the critical section but many of them in terms of different functions. In addition, we do also have shared variables that are accessed within these functions. For each of the different functions in a monitor to ensure only one of them is executed and no other process is executing on any of the functions, we can use a global semaphore called mutex.
Consider the example of the solution for the dining philosophers problem using monitors below.
monitor dining_philopher
{
enum {THINKING, HUNGRY, EATING} state[5];
condition self[5];
void pickup(int i) {
state[i] = HUNGRY;
test(i);
if (state[i] != EATING)
self[i].WAIT();
}
void putdown(int i) {
state[i] = THINKING;
test((i + 4) % 5);
test((i + 1) % 5);
}
void test(int i) {
if (
(state[(i + 4) % 5] != EATING) &&
(state[i] == HUNGRY) &&
(state[(i + 1) % 5] != EATING))
{
state[i] = EATING;
self[i].SIGNAL();
}
}
initialization code() {
for (int i = 0; i < 5; i++)
state[i] = THINKING;
}
}
}
Ideally, how a process might invoke these functions would be in the following sequence:
DiningPhilosophers.pickup(i);
...
// do somework
...
DiningPhilosophers.putdown(i);
Now, whilst one process is executing inside the pickup() method another might try to invoke putdown() (or even the pickup) method. In order to ensure mutual exclusion we must ensure only one process is running inside the monitor at any given time. So, to handle these cases we have a global semaphore mutex that encapsulates all the invokable (pickup & putdown) methods. So these two methods will be implemented as follows:
void pickup(int i) {
// wait(mutex);
state[i] = HUNGRY;
test(i);
if (state[i] != EATING)
self[i].WAIT();
// signal(mutex);
}
void putdown(int i) {
// wait(mutex);
state[i] = THINKING;
test((i + 4) % 5);
test((i + 1) % 5);
// signal(mutex);
}
Now only one process will be able to execute inside the monitor in any of its methods. Now, with this setup, if Process P1 has executed pickup() (but is yet tp putdown the chopsticks) and then Process P2 (say an adjacent diner) tries to pickup(): since his/her chopsticks (shared resource) is in use, it has to wait() for it to be available. Let's look at the WAIT and SIGNAL implementation of the monitor's conditional variables:
WAIT(){
x_count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x_sem);
x_count--;
}
SIGNAL() {
if (x_count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
}
The WAIT implementation of the conditional variables is different from that of the Semaphore's because it has to provide more functionality, like allowing other processes to invoke functions of the monitor (whilst it waits) by releasing the mutex global semaphore. So, when WAIT is invoked by P2 from the pickup() method, it will call signal(mutex) allowing other processes to invoke the monitor methods and call wait(x_sem) on the semaphore specific to the conditional. Now, P2 is blocked here. In addition, the variable x_count keeps track of the number of Processes waiting on the conditional variable (self).
So when P1 invokes putdown(), this will invoke SIGNAL via the test() method. Inside SIGNAL when P1 invokes signal(x_sem) on the chopstick it holds, it must do one additional thing. It must ensure that only one process is running inside the monitor. If it would only call signal(x_sem) then from that point onwards P1 and P2 both would start doing things inside the monitor. To prevent this P1, after releasing its chopstick it will block itself until P2 finishes. To block itself, it uses the semaphore next. And to notify P2 or some other process that there is someone blocked it uses a counter next_count.
So, now P2 would get the chopsticks and before it exits the pickup() method it must release P1 who is waiting on P2 to finish. So now, we must change the pickup() method (and all functions of the monitor) as follows:
void pickup(int i) {
// wait(mutex);
state[i] = HUNGRY;
test(i);
if (state[i] != EATING)
self[i].WAIT();
/**************
if (next_count > 0)
signal(next);
else
signal(mutex);
**************/
}
void putdown(int i) {
// wait(mutex);
state[i] = THINKING;
test((i + 4) % 5);
test((i + 1) % 5);
/**************
if (next_count > 0)
signal(next);
else
signal(mutex);
**************/
}
So now, before any process exits a function of the monitor, it checks if there are any waiting processes and if so releases them and not the mutex global semaphore. And the last of such waiting processes will release the mutex semaphore allowing new processes to enter into the monitor functions.
I know it's pretty long, but it took some time for me to understand and wanted to put it in writing. I will post it on a blog soon.
If there are any mistakes please let me know.
Best,
Shabir
I agree its confusing.
Lets first understand the first piece of code:
// if you are the only process on the queue just take the monitor and invoke the function F.
wait(mutex);
...
body of F
...
if (next_count > 0)
// if some process already waiting to take the monitor you signal the "next" semaphore and let it take the monitor.
signal(next);
else
// otherwise you signal the "mutex" semaphore so if some process requested the monitor later.
signal(mutex);
back to your questions:
What does the reason for introducing semaphore next and the count
next_count of processes suspended on next mean?
imagine you have a process that is doing some I/O and it needs to be blocked until it finishes. so you let other processes waiting in the ready queue to take the monitor and invoke the function F.
next_count is only for the purpose to keep track of processes waiting in the queue.
a process suspended on next semaphore is the process who issued wait on condition variable so it will be suspended until some other
process (next process) wake it up and resume work.
Why are x.wait() and x.signal() implemented the way they are?
Lets take the x.wait():
semaphore x_sem; // (initially = 0)
int x_count = 0; // number of process waiting on condition (x)
/*
* This is used to indicate that some process is issuing a wait on the
* condition x, so in case some process has sent a signal x.signal()
* without no process is waiting on condition x the signal will be lost signal (has no effect).
*/
x_count++;
/*
* if there is some process waiting on the ready queue,
* signal(next) will increase the semaphore internal counter so other processes can take the monitor.
*/
if (next_count > 0)
signal(next);
/*
* Otherwise, no process is waiting.
* signal(mutex) will release the mutex.
*/
else
signal(mutex);
/*
* now the process that called x.wait() will be blocked until other process will release (signal) the
* x_sem semaphore: signal(x_sem)
*/
wait(x_sem);
// process is back from blocking.
// we are done, decrease x_count.
x_count--;
Now lets take the x.signal():
// if there are processes waiting on condition x.
if (x_count > 0) {
// increase the next count as new blocked process has entered the queue (the one who called x.wait()). remember (wait(x_sem))
next_count++;
// release x_sem so the process waiting on x condition resume.
signal(x_sem);
// wait until next process is done.
wait(next);
// we are done.
next_count--;
}
Comment if you have any questions.
In order to gurantee Bounded wait in Test and set Instruction,following is the code given in Operating system book,Galvin -:
do {
1 waiting[i] = true;
2 while (waiting[i] && test_and_set(&lock)) ;
3 waiting[i] = false;
/* critical section */
4 j = (i + 1) % n;
5 while ((j != i) && !waiting[j])
6 j = (j + 1) % n;
7 if (j == i)
8 lock = false;
9 else
10 waiting[j] = false;
/* remainder section */
} while (true);
I am getting the complete code and concluded that
A process P_i will be in the critical section if either
Waiting [i]=false or test_and_set(&lock)=FALSE which ensures that Lock was FALSE previously. so Exit Section is either setting Waiting[j] or lock to FALSE.
But i have got some doubts-:
if in the exit section section it is found that same process again requests for critical section i.e
if j==i
then according to the code,that process have to start its execution form line number 2,i.e will execute
test_and_set(&lock))
in while loop and find the return value of test_and_set(&lock)) as false and then move to critical section.My doubt is that if same process wants to be in critical section ,is it necessary to start its exection right from line number 2
2.Now i want to do following Permutation and want to check the possible outcome.i want to swap line number 8 and 10
in line number 8 if i make
waiting[j]=false;
then also it will move to critical section even though lock =true now.
in line number 10 if i make
lock=false
then also it(process p_j) will move to critical section even though waiting[i]=true and i think it would be better because line number 3 will assign waiting[i]=false ,after the while loop breaks due to test_and_set(&lock)=false.
On the other hand if i make this change process have to execute test_and_set(&lock) which is time consuming
Is my assumption for point2 right?
what is the correct reason for point 1?
Thanks
Regarding point 1:
My doubt is that if same process wants to be in critical section ,is
it necessary to start its exection right from line number 2
A process is basically an program in execution. A process just cannot jump around choosing which instruction to execute next. The control flow decides that. The control of the code(which is the process itself) suggests that if a process successfully enters critical section, and again wants to enter critical section, then it will first execute lines 4 to 10 and then execute remainder section and would have to start execution right from line 1
Regarding your point 2
Now i want to do following Permutation and want to check the possible
outcome.i want to swap line number 8 and 10
If you swap the lines, the bounded waiting condition would no longer exist.
Proof
Suppose that only 1 process P(i) made the request to access Critical Section and it successfully entered. So
lock = true and waiting[i] = true
because only then it would have been able to come out of the for loop. Now it starts executing from line 4
Then j takes following values:
i + 2 , i + 3, ......0 , 1 , 2 , 3 , 4....i
wrap around of values occurs because of % operator. And Because no other process made request to enter critical section, waiting[j] = false for j != i
Therefore the condition while ((j != i) && !waiting[j]) becomes false when j equals i, and now we are at line 7. The new code is:
if (j == i)
waiting[j] = false;
else
lock = false;
Now if any process makes a request to enter critical section, then while (waiting[i] && test_and_set(&lock)) ; would always evaluate to true because lock is true and waiting[i] is also true and it would be stuck in spinlock. There would be no progress.