Concurrent programming, how do i construct a semaphore? - multithreading

i have a project where i have to write pseudocode for a semaphore, from the following text:
"Consider a scenario where a single taxi is taking Manchester United and Liverpool supporters from the city centre to the Saturday football game. The taxi can take four supporters at a time and it is always filled to capacity when carrying supporters. However the situation is never allowed to arise where the taxi contains one supporter of either team isolated on their own. The taxi carries out a number of trips and when it first arrives it randomly signals to one of the two waiting supporters’ queues. You can assume that there are always one or more supporters waiting in each queue when it is signaled. When a supporter enters the taxi and there is still some room for more supporters in the taxi the supporter (who has just joined the taxi) signal to another waiting supporter in one of the queues for them to also enter the taxi. Where possible the supporter will randomly select the queue to signal, however if necessary they will select a particular queue so as to ensure that no single supporter will be isolated in the taxi with opposing supporters.
The last supporter entering the taxi to complete a full cohort of four supporters in the taxi signals the taxi (driver) to take them to the football ground. The taxi takes them to their destination and then returns to repeat the cycle. Note that only the supporters (not the taxi driver) are able to differentiate between who is a Manchester United supporter and who is a Liverpool supporter."
I'm having trouble applying what notes i have, and what help there is online to this scenario.
Heres what ive done so far:
int numManInTaxi = 0; //current no. of ManU supporters in taxi
int numLivInTaxi = 0;
sem MaxUnitedFans = 4; // // max no. of supporters that can fit in taxi
sem MaxLivFans = 4;
sem MMutexSem = 1;
sem LMutexSem = 1;
CO
for (count = 1 to ManUSupporter){
ManUProcess[count];
//
for (count = 1 to LivSupporter){
LivProcess[count];
OC
} /*end main process
process ManUProcess [i = 1 to N]{
P(MMutexSem); // mutually exclusice access for United supporter
numManUInTaxi++;
if ((numManInTaxi+numLivInTaxi) < 4)
{
if (numManuInTaxi == 3) { // signal the Man queue
numManUInTaxi++;
} else if ((numManUInTaxi ==1) && (numLivInTaxi==2)){
numManUInTaxi++;
} else if ( (numManInTaxi == 2) &&(numLivInTaxi==1)) {
V(MMutexSem);
NumLivInTaxi++;}
//end ManU supporter semaphore

Here is what I could make-
int numManInTaxi = 0; //current no. of ManU supporters in taxi
int numLivInTaxi = 0;
int seats=4; //no of seats available empty
sem taxi=1; //to wait for taxi to send signal
sem seats=0; //signal generated by taxi or passenger for next passenger
wait(taxi); //taxi is available
{
signal(seat); //taxi generates signal
while(wait(seats)) //check if there are seats available
{
int i=rand()%2; //random number 0 or 1 used to select between 2 queues
if(i==0)
numManInTaxi++; //passenger supports ManU
else
numLivInTaxi++; //passenger supports Liv
seats--;
if(seats>1) //passenger generates signal for next passenger to enter
signal(seat);
}
/*Now three seats are filled and we have one empty seat left which is to
be filled such that there is no lone supporter of a team in taxi*/
signal(seat); //signal for last seat
wait(seat); //last passenger recieves the signal
seats--;
if(numManInTaxi==1) //if only one supporter belongs to ManU
numManInTaxi++;
else
numManInTaxi++;
}
//taxi drops passengers
numManInTaxi=0;
numManInTaxi=0;
seats=4;
signal(taxi); //taxi is ready for next trip

Related

POSIX implementation of a named semaphore for IPC

I am working on a homework assignment involving implementing a semaphore to enforce mutual exclusion between child processes. I have most of the code working, except that I am not using the semaphore correctly. The articles I have found aren't helping much. Could someone explain to me how the POSIX semaphore works?
For example, If i had a parent process spawn child processes using fork() and execl():
sem=sem_open("/semaphore1",O_CREAT|O_EXCL,S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,1);
for (i = 0; i < 3; i++)
{
//three child process are spawned in the image of the parent
child[i] = fork();
//establish whether all children were created successfully
switch (child[i])
{
//child process creation failed...
case -1:
rpterror ((char *)"fork failure", pname);
exit(1);
//given that the fork() was successful (the children were spawned successfully)...
case 0:
sprintf (pname, "shmc%d", i+1);
execl("shmc1", pname, ascshmid, (char *)0);
perror ("execl failed");
exit (2);
}
}
and the children wanted to access and modify a value in a shared memory segment (created by the parent):
sem=sem_open("/semaphore1", O_RDWR);
while ( !all_out)
{ /* loop to sell all seats */
/* puts the process to sleep for an amount of time, then decreases the amount of seats available. Before printing out the new count of seats, the process sleeps again. Finally, it prints the seat count until there are no more seats left.*/
if (class_ptr->seats_left > 0)
{
sem_wait(sem);
sleep ( (unsigned)rand()%5 + 1);
class_ptr->seats_left--;
sleep ( (unsigned)rand()%5 + 1);
cout << pname << " SOLD SEAT -- " << class_ptr->seats_left << " left" <<endl;
sem_post(sem);
}
else
{
all_out++;
cout << pname << " sees no seats left" << endl;
}
sleep ( (unsigned)rand()%10 + 1);
}
where seats_left is the shared variable.
running this code gives me an output that looks like this. The shared variable has an initial value of 15:
shmc1 SOLD SEAT -- 14 left
shmc2 SOLD SEAT -- 13 left
shmc3 SOLD SEAT -- 12 left
shmc1 SOLD SEAT -- 11 left
shmc2 SOLD SEAT -- 10 left
shmc3 SOLD SEAT -- 9 left
shmc1 SOLD SEAT -- 8 left
shmc2 SOLD SEAT -- 7 left
shmc3 SOLD SEAT -- 6 left
shmc2 SOLD SEAT -- 5 left
shmc1 SOLD SEAT -- 4 left
shmc3 SOLD SEAT -- 3 left
shmc2 SOLD SEAT -- 2 left
shmc1 SOLD SEAT -- 1 left
shmc1 sees no seats left
shmc3 SOLD SEAT -- 0 left
shmc3 sees no seats left
shmc2 SOLD SEAT -- -1 left
shmc2 sees no seats left
Parent removing shm
As you can see, towards the end is where my processes enter critical section at the same time another process is doing so. Does anyone have any idea why that is?
Try moving the sem_wait() outside of the if statement:
sem=sem_open("/semaphore1", O_RDWR);
while (!all_out) {
sem_wait(sem);
if (class_ptr->seats_left > 0) {
sleep((unsigned)rand()%5 + 1);
class_ptr->seats_left--;
sleep((unsigned)rand()%5 + 1);
cout << pname << " SOLD SEAT -- " << class_ptr->seats_left << " left" <<endl;
}
else {
all_out++;
cout << pname << " sees no seats left" << endl;
}
sem_post(sem);
sleep((unsigned)rand()%10 + 1);
}
I don't think you have an issue with processes not respecting the critical segment (although semaphores are sort of an honor system, just like regular stop lights..). I think the problem is just that process B is waiting on the lock, which is held by process A, and when A sells the last ticket and relases the lock, B grabs the lock and sells another ticket, because it already checked if tickets were available and never checks again before selling that last one.
If you run this enough times, you'll probably see instances of zero, one and two tickets being oversold.

One lane bridge using monitor

In the University I'm given this canonical parallel programming problem from "Gregory R. Andrews-Foundations of Multithreaded .... programming": (though I have a newer and Russian edition of the book I found an old English variant and try to convey everything properly)
I was also given task to solve this problem but with m consequently moving cars possible using semaphores To solve that task I was told by the tutor to mimic Reader's behavior from readers-writers task
The One-Lane Bridge. Cars coming from the north and the south arrive at a one-
lane bridge. Cars heading in the same direction can cross the bridge at the same
time, but cars heading in opposite directions cannot.
Develop a solution to this problem. Model the cars as processes, and use a
monitor for synchronization. First specify the monitor invariant, then develop the
body of the monitor.Ensure fairness. (Have cars take tums)
I googled and found solution for analogous task (http://www.cs.cornell.edu/courses/cs4410/2008fa/homework/hw3_soln.pdf) but lecturer said most of it is useless and incorrect I ended up with the following solution:
monitor onelanebridge{
int nb=0,sb=0; //Invar:(nb==0 and sb<=1)or(sb=0 and nb<=1)
cond nbfreetogo,sbfreetogo; //conditional variables
procedure enter_n(){
if(sb!=0andnb==0) wait(nbfreetogo);
nb++;
}
procedure enter_s(){
if(nb!=0andsb==0) wait(sbfreetogo);
sb++;
}
procedure leave_n(){
nb--;
if(nb==0) signal(sbfreetogo);
}
procedure leave_s(){
sb--;
if(sb==0) signal(nbfreetogo);
}
}
I was asked the question "What ensures that no more than one car at a time can cross the bridge?".. And am not even sure whether it's even so... Please help me solve the task correctly. I must use only constructions from the above mentioned book...
Example of readers-writers problem solution from the book:
monitor RW_Controller {
int nr = 0, nw =0; //Invar: (nr == 0 or nw == 0) and nw <= 1
cond oktoread; # recieves signal, when nw == 0
cond oktowrite; # recieves signal, when nr == 0 и nw == 0
procedure request_read() {
while (nw > 0) wait(oktoread);
nr = nr + 1;
}
procedure release_read() {
nr = nr - 1;
if (nr == 0) signal(oktowrite);
# run one writer-process
}
procedure request_write() {
while (nr > 0 || nw > 0) wait(oktowrite);
nw = nw + 1 ;
}
procedure release_ write() {
nw = nw - 1;
signal(oktowrite); # run one writer-process and
signal_all(oktoread); # all reader-processes
}
}
Of course my solution is just a random try. Halp me please to solve the task properly
Note: A variable of "conditional variable" type according to the book is a "wait queue" which has these methods:
wait(cv)//wait at end of queue
wait(cv,rank)//wait in order of increasing value of rank
signal(cv)//awaken process at end of queue then continue
signal_all(cv)//awaken all processes at end of queue then continue
empty(cv) //true if wait queue is empty; false otherwise
minrank(cv) //value of rank of process at front of wait queue
And so I should solve the task probably using some of these
Your monitor onelanebridge is not far off the mark, but it has no notion of fairness. If there was a steady stream of northbound traffic, nothing would trigger a switch to southbound. You need to separate the count of waiting and ‘active’.
A simple fairness would be to alternate, so you could limit the ‘active’ counter at 1; and check whether to switch when it becomes zero.
To avoid inciting road rage, you might choose a limit based on the transit time of the single lane section.
You would now have vehicles waiting in enter_[ns] which had the right direction, but have to wait because of the limit, so your if (cond) wait needs to become while (more complex cond) wait.
Concurrent programming is not natural, but with practise can become ingrained. Try and think of the problem at hand rather than how can I employ these mechanisms.

Guidance for sleeping barber monitor solution

I am trying to write a monitor solution for the sleeping barber problem using two barbers and customers of three types who are either waiting solely for barber 1, barber 2 or may not care which barber cuts their hair.
I was hoping for guidance on this problem -
My thoughts so far are that the algorithm will utilize a single list for the waiting customers and can use procedures such as
try_to_get_haircut()
if_not_first()
wake_up_barber()
wait_for_haircut()
Below is one barber solution and i hope it'll guide for you.
monitor sleeping_barber{
condition wait_for_cust, wait_for_barber ;
int wait;
entry barber{
if (wait == 0) then cwait(wait_for_cust);
wait = wait - 1;
csignal(wait_for_barber); }
entry cut_customer_hair(){
if(wait < seat_num)
{
wait = wait + 1;
csignal(wait_for_cust);
cwait(wait_for_barber);
do_haircut();
}
}
{ wait = 0;}}

Qt5: How to execute a "task" based on a weekly scheduler?

I am using Qt5 on Windows7 platform.
I have an app running 24/24, that it's supposed to connect to some remote devices in order to open or close the service on them. Connection is done via TCP.
For each day of the week there is/should be the possibility to set the hour&minute for both operations/tasks: open-service and close-service, as in the code below:
#define SUNDAY 0
#define MONDAY 1
//...
#define SATURDAY 6
struct Day_OpenCloseService
{
bool automaticOpenService;
int openHour;
int openMinute;
bool automaticCloseService;
int closeHour;
int closeMinute;
};
QVector<Day_OpenCloseService> Week_OpenCloseService(7);
Week_OpenCloseService[SUNDAY].automaticOpenService = true;
Week_OpenCloseService[SUNDAY].openHour = 7;
Week_OpenCloseService[SUNDAY].openMinute = 0;
Week_OpenCloseService[SUNDAY].automaticCloseService = false;
//
Week_OpenCloseService[MONDAY].automaticOpenService = true;
Week_OpenCloseService[MONDAY].openHour = 4;
Week_OpenCloseService[MONDAY].openMinute = 30;
Week_OpenCloseService[MONDAY].automaticCloseService = true;
Week_OpenCloseService[MONDAY].closeHour = 23;
Week_OpenCloseService[MONDAY].closeMinute = 0;
// ...
Week_OpenCloseService[SATURDAY].automaticOpenService = true;
Week_OpenCloseService[SATURDAY].openHour = 6;
Week_OpenCloseService[SATURDAY].openMinute = 15;
Week_OpenCloseService[SATURDAY].automaticCloseService = false;
Week_OpenCloseService[SATURDAY].closeHour = 23;
Week_OpenCloseService[SATURDAY].closeMinute = 59;
If automaticOpenService is true for a day, then an open-service will be executed at the specified hour&minute, in a new thread (I suppose).
If automaticOpenService is false, then no open-service is executed for that day of the week.
And the same goes for the automaticCloseService...
Now, the question is:
How to start the open-service and close-service tasks, based on the above "scheduler"?
Ok, the open-service and close-service tasks are not implemented yet, but they will be just some simple commands via TCP connection to the remote devices (which are listening on a certain port).
I'm still weighing on how to implement that, too... (single-thread, multi-thread, concurrent, etc).
A basic implementation of a scheduler will hold a list of upcoming tasks (maybe with just two items in the list in your case) that is kept sorted by the time at which those tasks need to be executed. Since you are using Qt, you could use QDateTime objects to represent the times at which your upcoming tasks need to be done.
Once you have that list set up, it's just a matter of calculating how many seconds remain between the current time and the timestamp of the first item in the list, and then waiting that number of seconds. The QDateTime::secsTo() method is very useful here as it will do just that calculation for you. You can then call QTimer::singleShot() to make it so that a signal will be emitted in that-many seconds.
When the qTimer's signal is emitted and your slot-method is called, you slot method will check the QDateTime of the first item in the list; if the current time is greater than or equal to that item's QDateTime, then it's time to execute the task, and the pop that item off the head of the list (and maybe reschedule a new task for tomorrow?). Repeat until either the list is empty or the first item in the list has a QDateTime that is still in the future, in which case you'd go back to step 1 again. Repeat indefinitely.
Note that multithreading isn't required to accomplish this task under Qt (and using multithreading wouldn't make the task any easier, either, so I'd avoid it if possible).

MPI_Recv message ordering vs MPI_Send message ordering

While trying to simulate the behaviour of a network using OpenMPI, I am experiencing an issue which can be summed up as follows:
Rank 2 sends a message (message1) to rank 0;
Rank 2 sends a message (message2) to rank 1;
Rank 2 sends a message (message3) to rank 0;
At his own turn, rank 0 receives both messages from rank 2 and forwards them to rank 1 (in the correct order);
Rank 1 receives the messages in the following order: message1, message3 and message2.
This behaviour only occurs only once in a while running the program. Usually (6 times out of 7), following the same pattern, rank 1 appears to receive the messages in the expected order (i.e: message2, message1, message3)
I am only using the basic MPI_Recv and MPI_Send functions.
MPI makes no guarantee about the order in which messages from different processes will be recieved. In fact, a receive operation can begin after a send has completed if an output buffer is used in standard mode: http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node40.html#Node40. The only order you can guarantee with standard mode send is that message3 will always arrive after message1. Here is a possible (not unique) sequence that would lead to your anomalous scenario:
Rank 2 sends a message (message1) to rank 0;
Rank 0 receives message1 from rank2;
Rank 0 sends a message (message1) to rank 1;
Rank 1 receives message1 from rank0;
Rank 2 sends a message (message2) to rank 1;
Rank 2 sends a message (message3) to rank 0;
Rank 0 receives message3 from rank2;
Rank 0 sends a message (message3) to rank 1;
Rank 1 receives message3 from rank0;
Rank 1 receives message2 from rank2;
Essentially, MPI_Send is an alias for either MPI_BSend or MPI_SSend, and it is not up to you which one is picked. Your anomaly is caused by MPI_BSend. You can guarantee a write to the corresponding receive buffer using synchronous mode (MPI_SSend) or ready mode (MPI_RSend). The main diffrerence between the two is that ready mode requires the receiver to already be waiting for the message for it not to fail, while synchronous mode will wait for it to happen.
If you are on a Linux platform, you can play with the standard mode by using the nice command to increase the priority of rank0 and decrease that of rank2. The anomaly should happen more consistently the more you increase the priority difference. Here is a brief tutorial on the subject: http://www.nixtutor.com/linux/changing-priority-on-linux-processes/

Resources