Program is starved (no output) after adding usleep() in the threads - c++

So I'm simulation a car intersection with four queues (for each direction) and a global intersection Q. The program runs fine without the usleep (which is commented out). But when I use usleep, nothing happens.
I'm sure its because the localID that gets pushed into the globalQ is different than the one that gets pushed in the local (directional) queue.
So this line "if ((localID == northQ.front()) && (localID == globalQ.front()))"
is never satisfied.
Reason I am introducing "usleep(getrand(100000, 3000000));" is because I want to add some randomness to the cars' speeds. I know it might be a bit confusing. But the major point is the program runs without the sleep command. But when I introduce it, nothing happens... Some starvation I guess.
EDIT: The main 4 functions are the same thing. Just different queue names.
EDIT2: The program works if I sleep for a certain amount of time. It doesn't work when that time is a random number in some interval that I specify.
The code:
// Instructions
// Change the CARS and RUN_TIME variable to the desired values.
// Compile in command line using: g++ -pthread Intelligent_Traffic_Light_System.cpp -o run.exe
// Run in command line by using: ./run.exe
#include <iostream>
#include <pthread.h>
#include <queue>
#include <cstdlib> //for rand()
#include <unistd.h> // for usleep()
#include <ctime> //for clock(), clock_t, CLOCKS_PER_SEC
#define CARS 10 // # cars coming from each direction. 40 cars total
#define RUN_TIME 125 // 125 seconds (5 seconds longer than it should take to run)
using namespace std;
int globalID; // global ID for each car arriving at the intersection
// a queue for each direction.
queue<int> northQ;
queue<int> eastQ;
queue<int> southQ;
queue<int> westQ;
queue<int> globalQ;
pthread_t threadID;
// a lock for each queue/direction.
pthread_mutex_t northLock;
pthread_mutex_t eastLock;
pthread_mutex_t southLock;
pthread_mutex_t westLock;
pthread_mutex_t globalQlock;
pthread_mutex_t globalIDLock; // lock for changing the globalid (i.e. car id)
pthread_mutex_t intersectionLock; // lock for one car passing through the intersection
int getrand(int min,int max) //random number generator between min and max
{
return(rand()%(max-min)+min);
}
void init()
{
globalID = 1; //first car will have ID = 1
pthread_mutex_init(&northLock, NULL);
pthread_mutex_init(&eastLock, NULL);
pthread_mutex_init(&southLock, NULL);
pthread_mutex_init(&westLock, NULL);
pthread_mutex_init(&globalIDLock, NULL);
pthread_mutex_init(&intersectionLock, NULL);
pthread_mutex_init(&globalQlock, NULL);
}
// Now will test to create an intersection with only 1 direction. North
void *north(void *null)
{
int localID;
double duration; //for checking how long a car will be waiting at the front of its lane
clock_t start; //variable will be used to calculate wait time
pthread_mutex_lock(&northLock); // locking the queue
pthread_mutex_lock(&globalIDLock); // locking globalIDLock mutex in order to update globalID
localID = globalID++; // update globalID after reserving that ID for a car in north lane
pthread_mutex_unlock(&globalIDLock);
northQ.push(localID); // pushing the local car into northQ.
pthread_mutex_unlock(&northLock);
//usleep(getrand(100000, 3000000)); //lets say it takes somewhere between 1/10th of a second and 3 seconds to get to the intersection.
start = clock(); // Now the car has arrived at intersection. Let's start the timer.
pthread_mutex_lock(&globalQlock);
globalQ.push(localID);//pushing car into global (intersection Q)
//cout << localID <<endl;
pthread_mutex_unlock(&globalQlock);
while(1) //Checking cars properties here
{
if ((localID == northQ.front()) && (localID == globalQ.front())) // Current Car is in the front of the lane... Lets Proceed
{
break;
}
else //Current car is not in front on its lane. Lets wait
{
usleep(10); // sleep for 10 microsecond to allow for other cars to proceed if they must
continue;
}
}
// Car is in the front so let's proceed to allow it to pass through intersection.
pthread_mutex_lock(&intersectionLock); // need to lock the intersection. Function call will block until mutex is available
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
northQ.pop();
globalQ.pop();
cout << "Car from NORTH lane with ID: " << localID << " ENTERING the intersection." << endl;
cout << "It has been waiting at the light for: "<< duration<<" seconds."<<endl;
sleep(3);
cout << "Car from NORTH lane with ID: " << localID << " LEAVING the intersection." << endl<<endl;
pthread_mutex_unlock(&intersectionLock); // give other cars a chance to pass
}
void *east(void *null)
{
int localID;
double duration;
clock_t start;
pthread_mutex_lock(&eastLock); // locking the queue
pthread_mutex_lock(&globalIDLock); // locking globalIDLock mutex in order to update globalID
localID = globalID++; // update globalID after reserving that ID for a car in north lane
pthread_mutex_unlock(&globalIDLock);
eastQ.push(localID); // pushing the local car into northQ.
pthread_mutex_unlock(&eastLock);
//usleep(getrand(100000, 3000000)); //lets say it take 1/10th of a second to get to the intersection.
start = clock();
pthread_mutex_lock(&globalQlock);
globalQ.push(localID);//pushing car into global queue (i.e. intersection queue)
pthread_mutex_unlock(&globalQlock);
while(1) //Checking cars properties here
{
if ((localID == eastQ.front()) && (localID == globalQ.front())) // Current Car is in the front of the lane... Lets Proceed
{
break;
}
else //Current car is not in front on its lane. Lets wait
{
usleep(10); // sleep for 10 microsecond to allow for other cars to proceed if they must
continue;
}
}
// Car is in the front so let's proceed to allow it to pass through intersection.
pthread_mutex_lock(&intersectionLock); // need to lock the intersection. Function call will block until mutex is available
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
eastQ.pop();
globalQ.pop();
cout << "Car from EAST lane with ID: " << localID << " ENTERING the intersection." << endl;
cout << "It has been waiting at the light for: "<<duration<<" seconds."<<endl;
sleep(3);
cout << "Car from EAST lane with ID: " << localID << " LEAVING the intersection." << endl <<endl;
pthread_mutex_unlock(&intersectionLock); // give other cars a chance to pass
}
void *south(void *null)
{
int localID;
double duration;
clock_t start;
pthread_mutex_lock (&southLock); // locking the queue
pthread_mutex_lock (&globalIDLock); // locking globalIDLock mutex in order to update globalID
localID = globalID++; // update globalID after reserving that ID for a car in north lane
pthread_mutex_unlock (&globalIDLock);
southQ.push(localID); // pushing the local car into northQ.
pthread_mutex_unlock (&southLock);
//usleep(getrand(100000, 3000000)); //lets say it take 1/10th of a second to get to the intersection.
start = clock();
pthread_mutex_lock(&globalQlock);
globalQ.push(localID);//pushing car into global (intersection Q)
pthread_mutex_unlock(&globalQlock);
while(1) //Checking cars properties here
{
if ((localID == southQ.front()) && (localID == globalQ.front())) // Current Car is in the front of the lane... Lets Proceed
{
break;
}
else //Current car is not in front on its lane. Lets wait
{
usleep(10); // sleep for 10 microsecond to allow for other cars to proceed if they must
continue;
}
}
// Car is in the front so let's proceed to allow it to pass through intersection.
pthread_mutex_lock(&intersectionLock); // need to lock the intersection. Function call will block until mutex is available
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
southQ.pop();
globalQ.pop();
cout << "Car from SOUTH lane with ID: " << localID << " ENTERING the intersection." << endl;
cout << "It has been waiting at the light for: "<<duration<< " seconds."<<endl;
sleep(3);
cout << "Car from SOUTH lane with ID: " << localID << " LEAVING the intersection." << endl<<endl;
pthread_mutex_unlock(&intersectionLock); // give other cars a chance to pass
}
void *west(void *null)
{
int localID;
double duration;
clock_t start;
pthread_mutex_lock (&westLock); // locking the queue
pthread_mutex_lock (&globalIDLock); // locking globalIDLock mutex in order to update globalID
localID = globalID++; // update globalID after reserving that ID for a car in north lane
pthread_mutex_unlock (&globalIDLock);
westQ.push(localID); // pushing the local car into northQ.
pthread_mutex_unlock (&westLock);
//usleep(getrand(100000, 3000000));
start = clock();
pthread_mutex_lock(&globalQlock);
globalQ.push(localID);//pushing car into global (intersection Q)
pthread_mutex_unlock(&globalQlock);
while(1) //Checking cars properties here
{
if ((localID == westQ.front()) && (localID == globalQ.front())) // Current Car is in the front of the lane... Lets Proceed
{
break;
}
else //Current car is not in front on its lane. Lets wait
{
usleep(10); // sleep for 10 microsecond to allow for other cars to proceed if they must
continue;
}
}
// Car is in the front so let's proceed to allow it to pass through intersection.
pthread_mutex_lock(&intersectionLock); // need to lock the intersection. Function call will block until mutex is available
duration = ( std::clock() - start ) / (double) CLOCKS_PER_SEC;
westQ.pop();
globalQ.pop();
cout << "Car from WEST lane with ID: " << localID << " ENTERING the intersection." << endl;
cout << "It has been waiting for: "<< duration <<" seconds."<< endl;
sleep(3);
cout << "Car from WEST lane with ID: " << localID << " LEAVING the intersection." << endl<<endl;
pthread_mutex_unlock(&intersectionLock); // give other cars a chance to pass
}
int main()
{
init();
for(int i = 0; i < CARS; i++) //first car will be car with ID 1; Last ID is 40
{
pthread_create (&threadID, NULL, north, NULL);
pthread_create (&threadID, NULL, east, NULL);
pthread_create (&threadID, NULL, south, NULL);
pthread_create (&threadID, NULL, west, NULL);
}
sleep(RUN_TIME); //sleep for sufficient times to allow for all threads to finish running.
cout << "Finished." << endl;
return 0;
}

It seems that the main thread exits before the "north"-"east" etc threads terminate:
When I put the sleep(RUN_TIME) inside the main loop, the program starts working.
The reason of the early termination is the (localID == globalQ.front()) not synchronized code located inside each "north"-"east" function. This code, as you have correctly mentioned, is never (almost) satisfied and causes to busy wait inside the while(1) loop.

Related

Having set amount of thread to work as consumers

I have created a producer / consumer code as following
class CTest{
public:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
void ConsumerInit( int threads ){
for( int i = 0; i < threads; i++ ){
thrs.push_back(thread(&CTest::consumer, this ,i));
}
}
void waitForTHreads(){
for( auto &a : thrs )
a.join();
}
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
private:
queue<int> q;
vector<thread> thrs;
mutex m;
condition_variable cnd;
};
and main
int main(){
int x;
CTest t;
int counter = 0;
while( cin >> x ){
if( x == 0 ){
cout << "yay" << endl;;
break;
}
if( x == 1)
t.producer(counter++);
if( x == 2 )
t.ConsumerInit(5);
}
t.waitForTHreads();
t.printQueue();
return 0;
}
What this code does it , when user inputs "1" it will add number to the queue ,when user inputs "2" , 5 threads are spawned to retrieve data from queue and print it. However my problem is as followng , when i input
6 numbers , only 5 of them are printed due to fact that only 5 threads are spawned , what i want to do is thread to retrieve a data from queue , print int, and then again waiting if it can print another data. This way all N > 5 numbers would pri printed with just 5 threads.
My question is , what is standard way how to achieve this? I read few documens but didnt fint/cannot think of good solution. How are problems like this solved?
when i try to create simple thread pool :
void consumer(int i ){
while(true){
{
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
cout << "Producer " << i << " got " << tmp << endl;
} //consumer(i);
}
}
and input N number all numbers are processed by one thread.
Thanks for help!
The current version of consumer can only read one value before exiting. In order to read more, it must loop, and this leads to your second version of consumer which has two problems:
Consumption here is so quick that the first thread into the queue can consume the whole queue within its timeslice (or however CPU is being allocated). Insert a yield or a sleep to force the OS to switch tasks.
The mutex is not unlocked so no other threads are able to get in.
Fortunately you aren't creating the threads until you need them and they terminate after the queue is empty so the whole deal with conditional_variable can go out the window.
void consumer(int i)
{
unique_lock<mutex> l(m);
while (!q.empty())
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
// note: In the real world, locking around a cout is gross. cout is slow,
// so you want the unlock up one line. But...! This allows multiple threads
// to write to the consle at the same time and that makes your output
// look like it was tossed into a blender, so we'll take the performance hit
l.unlock(); // let other threads have a turn
this_thread::yield();
l.lock(); // lock again so the queue can be safely inspected
}
}
If you need to go with the threadpool approach, things get a little messier and the condition variable makes a return.
void consumer(int i)
{
while (true)
{
unique_lock<mutex> l(m);
if (q.empty())
{
cnd.wait(l);
}
if (!q.empty()) // OK. We got out of the conditional wait, but have
// other threads sucked the queue dry? Better check.
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
}
l.unlock();
this_thread::yield();
}
}
An atomic<bool> terminated may be helpful to allow an orderly shutdown while (true) does not allow for.
In general, without going into code details, a threadpool is created and the threads are put in a wait state (waiting on one or more events / signals, or in your case condition_variable cnd;) - I'm used to work with events, so I'll use that in the following text, but a condition_variable should work in a similar way.
When a task is added to the queue, a task-event is set/fired and one ore more threads wake up (depending on the event (single / multi)).
When a thread wakes up, it checks (with a lock) if there is a task available, if available, executes the task and when finished checks again (!) if there are more tasks waiting. (because when you add 8 tasks in one go, 5 threads become active, so they need to check if there are more tasks after finishing their first one.
If there are no jobs left, the thread goes back in the wait state (waiting for a next job, or a quit event).
When quitting the application, another, say quit-event, is set for all threads (you can't just wait for the threads to finish, because the threads themselves are waiting on an event to do some work) -- or you could fire the same event, and first set a volatile variable, which the threads should then first check on any event to see if they need to quit, or do another job. Then you can wait for the threads to 'come home'.
A lock should be held as short as possible.
As for your code:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
Here the lock is held longer than needed (and perhaps too long). You also just pushed a value, so q will not be empty (no need to check). Since you only add one item (task), only one thread should be woken up (so notify_one() should be fine here).
So you should: lock, push, unlock, notify - instead of unlock, you can place the lock and push inside brackets, which will trigger an unlock in the unique_lock<> destructor.
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
Here you should lock, check queue, pop if there is a task, unlock, if no task, put the thread in a wait state again, else do work with the popped value (after unlocking), and then check again if there is more work to do. Normally it is not a good idea to call cout while the data is locked.. but for a small test you could get away with it, especially because cout needs to be synchronized too (but it would be cleaner to synchronize cout on its own, separate from your data lock).
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
Make sure your data is locked here too! (although it's only called from main after the threads have finished, the function is in your class, and the data should be locked).

C++ multi thread programming with timer

I am new to multi thread programming, so this question might seem a little silly, but I really need to work this out so I can apply it to my project (which is way more complicated).
Follow is my code, I am trying to have 2 threads (parent and child) to update the same shared timer as they execute and stop when the timer reaches a specific limit.
But when I compile and execute this follow piece of code, there are 2 different outcomes: 1. child prints "done by child at 200000" but the program does not exit; 2. after child prints "done by child at 200000" and exits, parent keeps executing, prints a couple of dozen lines of "parent doing work" and "parent at 190000", then prints "done by parent at 200000" and the program exits properly.
The behavior I want is for whichever thread that updates the timer, hits the limit and exits, the other thread should stop executing and exit as well. I think I might be missing something trivial here, but I've tried changing the code in many ways and nothing I tried seem to work. Any help will be much appreciated :)
#include <iostream>
#include <unistd.h>
#include <mutex>
#include <time.h>
using namespace std;
mutex mtx;
int main () {
int rc;
volatile int done = 0;
clock_t start = clock();
volatile clock_t now;
rc = fork();
if (rc == 0) { //child
while (true) {
cout << "child doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
mtx.unlock();
break;
}
cout << "child at " << now << endl;
mtx.unlock();
}
_exit(0);
}
else { // parent
while (true) {
cout << "parent doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
mtx.unlock();
break;
}
cout << "parent at " << now << endl;
mtx.unlock();
}
}
return 0;
}
Multi-processes
Your code is multi-processes and not multi-threading: fork() will create a new separate process by duplicating the calling process.
The consequence: At the moment of the duplication, all the variables contain the same value in both processes. But each process has its own copy, so a variable modified in the parent will not be updated in the child's address space an vice-versa.
If you want to share variables between processes, you should have a look at this SO question
Multithread
For real multithreading, you should use std::thread. And forget about volatile, because it's not thread safe. Use <atomic> instead, as explained in this awesome video.
Here a first try:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <time.h>
using namespace std;
void child (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "child doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
}
cout << "child at " << now << endl;
this_thread::yield();
}
}
void parent (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "parent doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
}
cout << "parent at " << now << endl;
this_thread::yield();
}
}
int main () {
atomic<int> done{0};
clock_t start = clock();
atomic<clock_t> now;
thread t(child, std::ref(done), std::ref(now), start); // attention, without ref, you get clones
parent (done, now, start);
t.join();
return 0;
}
Note that you don't need to protect atomic accesses with a mutex, and that if you want to do, lock_guard would be recommended alternative.
This example is of course rather weak, because if you test an atomic variable if the if-condition, it's value might already have changed when entering the if-block. This doesn't cause a problem in your logic where "done" means "done". But if you'd need a more cauthious approach,
compare_exchange_weak() or compare_exchange_strong() could help further.

How to access info about a thread throughout a program

Question 1: I am trying to name each thread so it can be used throughout the program but am receiving errors like "request for member 'fid' in 'planes[t]' which is of non-class type 'pthread_t'. It is referring to use of planes[t].tid or use of planes[t].startState. I'm not sure how else to get/save these values for each individual thread.
Question 2: once I have a thread's startState, how can I send the thread to a takeoff() function (series of switch states and printfs).
Question 3: What should be passed into the StartState function? I'm trying to have each thread remember its start state so that later in the code I can have a flight be "landing" or "taking off."
Here is the relevant code: Updated 10/06 at 22:37
#include <pthread.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <unistd.h>
#include <algorithm>
#include <time.h>
#include <ctime>
#define NUM_THREADS 3 //3 flights
using std::queue;
using std::vector;
pthread_mutex_t runway1lock;
pthread_mutex_t runway2lock;
bool run1occupied;
bool run2occupied;
struct flight_data{ //each plane has these characteristics
//void *FlightID;
long fid;
int startState; // if start=1 ==> taking off ::: if start=2 ==> landing
int flyTime; //fly == randomly generated time (order) of takeoff/land
};
struct flight_data flightinfo[NUM_THREADS];
void *FlightID(void *flightid){
struct flight_data *my_flights;
my_flights = (struct flight_data*)flightid;
int taskid;
taskid = my_flights->fid;
// long fid;
// fid = (long)flightid;
// printf("Flight #%1d\n", tid);
pthread_exit(NULL);
}
void Start(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
int startState;
srand(time(0));
my_flights.startState = rand() % 2+1;
std::string startstring;
if(my_flights.startState == 1){
startstring = "Taking off";
}
if(my_flights.startState == 2){
startstring = "Landing";
}
for(int i = 1; i<NUM_THREADS+1; i++){
std::cout << "Start state for Flight # " << i << " is " << startstring << std::endl;
}
}
void takeoff(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
for(int i = 1; i<NUM_THREADS+1; i++){
int state = my_flights.startState;
switch(state){
case 1:{ //G (GATE)
std::cout << "Flight # " << flightinfo[i].fid << " is listed as waiting at the gate." << std::endl;
std::cout << "Flight # " << flightinfo[i].fid << "'s position in queue for runway: " << flightinfo[i].flyTime << std::endl;
sleep(3);
state = 2;
break;
}
case 2: { //Q (queue) -- sets order for use of runway
queue<pthread_t> queue;
vector<int> flightTimes;
int soonestFlightTime = 10;
flightTimes.push_back(flightinfo[i].flyTime); //put all flight times into a vector called flightTimes
std::sort(flightTimes.begin(), flightTimes.end()); //sort the vector of flightTimes low to high
std::reverse(flightTimes.begin(), flightTimes.end()); //flips vector -- high(front) to low(back)
while(!flightTimes.empty()){
if (flightinfo[i].flyTime == flightTimes.back()){ //if a thread has the soonest flight time
queue.push(i); //then put the flight in the runway queue
flightTimes.pop_back(); //pop off the soonest flight time
}
}
while(!queue.empty()){
if(flightinfo[i].fid == queue.front()){
state = 3;
queue.pop();
sleep(3);
}
}
break;
}
case 3: { //CLR (clearance for runway)
std::cout << "Flight # " << flightinfo[i].fid << " has clearance to move to the runway." << std::endl; //will go in order of queue
if(run1occupied){
sleep(3);
}
// else if(collide){
// state = 7;
// }
else{
state = 4;
}
break;
}
case 4: { //RTO (runway takeoff)
pthread_mutex_lock(&runway1lock);
run1occupied = true;
std::cout << "Flight # " << flightinfo[i].fid << " is taking off. Runway occupied. Stand by." << std::endl;
sleep(3);
pthread_mutex_unlock(&runway1lock);
run1occupied = false;
state = 5;
break;
}
case 5: { //CZ (cruise)
std::cout << "Flight # " << flightinfo[i].fid << " is reaching proper altitude and cruising toward destination." << std::endl;
sleep(3);
// if(!collide){
state = 6;
// }
// else{
// state = 7; //collision!!!
// }
break;
}
case 6: { //RMV (remove from monitoring list)
std::cout << "Flight # " << flightinfo[i].fid << " has been removed from the monitoring list." << std::endl;
break;
}
case 7:{ //COLL (collision)
std::cout << "Collision in the air. There were many casualties." << std::endl;
break;
}
}
}
}
void landing(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
for (int i = 0; i<NUM_THREADS; i++){
int state = my_flights.startState;
switch(state){
case 1:{ //ENTR (enter monitoring list)
state = 2;
break;
}
case 2:{ //Q (queue)
//if not the first thing in the queue then state = 4;
//otherwise state = 3;
}
case 3:{ //RWL (runway land)
state = 5;
break;
}
case 4:{ //HVR (hover)
//if first in queue then state = 3;
//otherwise stay here
//if collision state = 7;
}
case 5:{ //CLR (clearance to move to gate)
//if collision state = 7
//otherwise state = 6;
}
case 6:{ //G (gate)
}
case 7:{ //COLL (collision)
}
}
}
}
/*
bool collision(){
bool collide;
//random
if(){
collide = true;
}
else{
collide = false;
}
return collide;
}*/
int main(int argc, char *argv[]){
pthread_t flights[NUM_THREADS]; //pthread_t keeps a thread ID after the thread is created with pthread_create()
//it's like an index on a vector of threads
int *taskids[NUM_THREADS];
int rc;
long t;
for (t=1; t<=NUM_THREADS; t++){ //loop creates threads(flights)
printf("In main: Creating flight %1d\n", t);
flightinfo[t].fid= t;
rc = pthread_create(&flights[t], NULL, FlightID, (void *)&flights[t]);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
// Start(flightinfo[t]);
flightinfo[t].startState = rand() % 2+1;
std::cout << flightinfo[t].startState << std::endl;
if((flightinfo[t].startState)==1){
std::cout << "Flight # " << flightinfo[t].fid << " is listed with start state as " << flightinfo[t].startState << std::endl;
takeoff(flightinfo[t]);
//go to takeoff function and go through switch case
}
if((flightinfo[t].startState)==2){
std::cout << "Flight # " << flightinfo[t].fid << " is listed with start state as " << flightinfo[t].startState << std::endl;
landing(flightinfo[t]);
//go to landing function and go through switch case
}
}
pthread_exit(NULL);
}
It appears that you are confusing the pthread_t management variable, planes, with the variable containing the flight data, flights.
The pthread_t management variable, planes, is used by the pthread library and you should really only be using it as an argument to pthread library calls, otherwise just leave it alone and do not worry about it. Think of the variable planes as a storage area that you create and then give to the pthread library to use and by doing so you give ownership of that variable to the pthread library.
So the first order of business is to separate out and make distinct the difference between the pthread management and the actual data that is being manipulated by the threads.
You have several places where you are using the pthread management variable, planes, as if it is a flight data variable. It is not. Replace planes with flights
if((flights[t].startState)==1){
std::cout << "Flight # " << flights[t].fid << " is listed as waiting at the gate." << std::endl;
void takeoff();
//go to takeoff function and go through switch case
}
if((flights[t].startState)==2){
std::cout << "Flight # " << flights[t].fid << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
This bit of source in your function StartState() does not make sense.
for(int i = 0; i<NUM_THREADS; i++){
startState = rand() % 1+2;
}
startState = my_flights->startState;
I suppose you are wanting to set a start state of a particular flight with some random start state. So I would expect the source to look like the following as I assume you are interested in setting the start state for a specific flight and the loop does not really do anything except exercise the random number generator NUM_THREADS times so the loop should just be replaced by something like the following. However I have not checked your logic on this and whether the range is correct or anything.
my_flights->startState = rand() % 1+2;
A Suggested Course of Action
You should think of a thread as being a little program or application. I suggest that for this simple example that you first of all write your flight logic without worrying about threads. So if you start with a function, say FlyPlaneFlight () to which you pass a flight variable and this function then calls other functions to do various things and when the flight ends, it returns to the caller, you will probably be in a good place for the threads. After having the logic in place for a single flight, you then use the pthread library to create multiple flights by initializing the flight data, and then creating a thread, that uses FlyPlaneFlight().
You also need to consider time and interaction. For this kind of a simulation, I suspect that you will want to have the FlyPlaneFlight() function to have a loop in which changes are made to the flight data and then the thread will sleep for a second or two. As a beginning test, use a for loop with a definite number of iterations and will then exit such as the following:
for (int i = 0; i < 100; i++) {
// modify the flight data
sleep(1000); // sleep for a second (1000 milliseconds) then repeat
}
If this becomes more complicated so that the flights are not independent but must be synchronized in some way, you will need to look into the thread synchronization functions of the pthread library.
So when you wrap your FlyPlaneFlight() function into a pthread_create() function, it might look something like the following source snip:
void *FlightID(void *flightdata){
struct flight_data *my_flights = (struct flight_data*)flightdata;
// initialize the flight data as needed
FlyPlaneFlight (myFlight);
// print out the myFlight data so that you can see what happened
pthread_exit(NULL);
}
The idea is to treat the plane flight as an object and all of the needed data for the flight is in the struct flight_data struct and that for the most part you can ignore the pthread library which is not involved in the actual flying simulation but rather is used to allow for the simulation of multiple flying objects. So you create multiple threads, each of which has its own flight data and then uses the same code to process the flight data. You do a bit of randomization so that all of the various flights will have different histories, they will do different things.
Edit
Your main would then have a loop something like the following
for (t=0; t<NUM_THREADS; t++){ //loop creates threads(flights)
std::cout << "In main: Creating flight " << t+1 << std::endl;
flights[t].fid= t+1;
rc = pthread_create(&planes[t], NULL, FlightID, (void *)&flights[t]);
if (rc){
std::cout << "ERROR: return code from pthread_create() is " << rc << std::endl;
return (-1);
}
std::cout << "Created flight " << t << std::endl;
}
pthread_exit(NULL); // exit the main thread and allow remaining threads to complete
This will create your various threads and let them run. In the loop in the FlyPlaneFlight() function you would have the status print outs something like the following each time through the loop so your FlyPlaneFlight() function would look something like and you would use a kind of finite state machine to move from state to state possibly using a random number generator to roll a virtual dice using the rand() function as in these examples to determine the next state or to remain in the current state:
void FlyPlaneFlight (struct flight_data *my_flights)
{
for (int i = 0; i < 100; i++) {
switch (my_flights->startState) {
case 1:
std::cout << "Flight # " << my_flights->fid << " is listed as waiting at the gate." << std::endl;
// now move the flight state to the next state.
break;
case 2:
std::cout << "Flight # " << my_flights->fid << " is listed as waiting to land." << std::endl;
// now move the flight state to the next state.
break;
// other case statements for other flight states and moving between the
// various flight states.
}
sleep (1000); // sleep this thread for one second (1000 milliseconds) then repeat
}
}
EDIT #2 based on source update 10/06 at 22:37
In your source you have a global array variable, flights, that you are trying to access directly through out your source. This is a mistake that is leading you into problems. What you need to do is to have your thread create call to allocate a particular array element of flights to the particular thread. Then at that point you do not worry about the flights array but instead work with only the particular element assigned to that thread.
For instance use the thread create as follows which creates a thread and assigns a unique array element to the thread being created.
rc = pthread_create(&planes[t], NULL, FlightID, (void *)&flights[t]);
The thread entry function, FlightID() accepts as an argument a pointer to that array element so at that point any of your functions that operate on the flight data in flights[t] can just use that pointer to that array element. The functions should only be worried about their particular flight and not everyone else's flight as well.
Also after the thread is started, the function FlightID() and any function it calls should no longer be concerned about other threads so all these loops with NUM_THREADS in these functions should not be there.
The idea is to have a small program that is started by calling FlightID() which operates on the particular flight. Then with multiple threads each thread starts at FlightID(). So this is similar to the idea of main() being the entry point for a C/C++ program where main() has some arguments and your program starts at main(). In the case of threads, the thread starts at the thread entry function which in your case is FlightID().
The reason I have a loop in FlyPlaneFlight() is to provide a series of state changes for a finite state machine for a particular flight. In other words what is inside the loop is a plane flight.
Look at the difference between my suggested thread creation loop and your's. Mine does nothing more than create threads. Your's creates threads and then tries to do things with the flights array element which really should now belong to the thread created and not the main.
All those variables appear to be stored in the flights array, not the planes array.

bathroom synchronization and queue of threads

For homework we have been given the bathroom synchronization problem. I have been struggling trying to figure out how to start. What I would like to do when a person enter the restroom(personEnterRestrrom function), if they are female and no males are in the restroom they enter,if not they go into a queue for women waiting. I want to do the same for men. I tried to implement a queue that holds thread, but cannot get it to work. Then in personLeavesRestroom function. When a person leaves if no one is left in the bathroom the other queue starts. Here is my code, I know I am far off, by I do need some guidance and am not very familiar with semaphores.
//declarations
pthread_mutex_t coutMutex;
int menInBath;
int womanInBath;
int menWaiting;
int womenWaiting;
queue<pthread_mutex_t>men;
queue<pthread_mutex_t>women;
personEnterRestroom(int id, bool isFemale)
{
// LEAVE THESE STATEMENTS
pthread_mutex_lock(&coutMutex);
cout << "Enter: " << id << (isFemale ? " (female)" : " (male)") << endl;
pthread_mutex_unlock(&coutMutex);
// TODO: Complete this function
if(isFemale && menInBath<=0)
{
womanInBath++;
}
else if(isFemale && menInBath>0)
{
wait(coutMutex);
women.push(coutMutex);
}
else if(!isFemale && womanInBath<=0)
{
menInBath++;
}
else
{
wait(coutMutex);
men.push(coutMutex);
}
}
void
personLeaveRestroom(int id, bool isFemale)
{
// LEAVE THESE STATEMENTS
pthread_mutex_lock(&coutMutex);
cout << "Leave: " << id << (isFemale ? " (female)" : " (male)") << endl;
pthread_mutex_unlock(&coutMutex);
if(isFemale)
womanInBath--;
if(womanInBath==0)
{
while(!men.empty())
{
coutMutex=men.front();
men.pop();
signal(coutMutex);
}
}
}
If you are looking for FIFO mutex, this one could help you:
You gonna need:
mutex (pthread_mutex_t mutex),
array of condition variables (std::vector<pthread_cond_t> cond)
and queue for storing thread IDs (std::queue<int> fifo).
Let's say there is N threads with IDs 0 to N-1. Then fifo_lock() and fifo_unlock() could look like this (pseudocode):
fifo_lock()
tid = ID of this thread;
mutex_lock(mutex);
fifo.push(tid); // puts this thread at the end of queue
// make sure that first thread in queue owns the mutex:
while (fifo.front() != tid)
cond_wait(cond[tid], mutex);
mutex_unlock(mutex);
fifo_unlock()
mutex_lock(mutex);
fifo.pop(); // removes this thread from queue
// "wake up" first thread in queue:
if (!fifo.empty())
cond_signal(cond[fifo.front()]);
mutex_unlock(mutex);

Still having race condition with boost::mutex

I am trying an example, which causes race condition to apply the mutex. However, even with the mutex, it still happens. What's wrong? Here is my code:
#include <iostream>
#include <boost/thread.hpp>
#include <vector>
using namespace std;
class Soldier
{
private:
boost::thread m_Thread;
public:
static int count , moneySpent;
static boost::mutex soldierMutex;
Soldier(){}
void start(int cost)
{
m_Thread = boost::thread(&Soldier::process, this,cost);
}
void process(int cost)
{
{
boost::mutex::scoped_lock lock(soldierMutex);
//soldierMutex.lock();
int tmp = count;
++tmp;
count = tmp;
tmp = moneySpent;
tmp += cost;
moneySpent = tmp;
// soldierMutex.unlock();
}
}
void join()
{
m_Thread.join();
}
};
int Soldier::count, Soldier::moneySpent;
boost::mutex Soldier::soldierMutex;
int main()
{
Soldier s1,s2,s3;
s1.start(20);
s2.start(30);
s3.start(40);
s1.join();
s2.join();
s3.join();
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
}
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}
It looks like you're not waiting for the threads started in the loop to finish. Change the loop to:
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
s.join();
}
edit to explain further
The problem you saw was that the values printed out were wrong, so you assumed there was a race condition in the threads. The race in fact was when you printed the values - they were printed while not all the threads had a chance to execute
Based on this and your previous post (were it does not seem you have read all the answers yet). What you are looking for is some form of synchronization point to prevent the main() thread from exiting the application (because when the main thread exits the application all the children thread die).
This is why you call join() all the time to prevent the main() thread from exiting until the thread has exited. As a result of your usage though your loop of threads is not parallel and each thread is run in sequence to completion (so no real point in using the thread).
Note: join() like in Java waits for the thread to complete. It does not start the thread.
A quick look at the boost documentation suggests what you are looking for is a thread group which will allow you to wait for all threads in the group to complete before exiting.
//No compiler so this is untested.
// But it should look something like this.
// Note 2: I have not used boost::threads much.
int main()
{
boost::thread_group group;
boost::ptr_vector<boost::thread> threads;
for(int loop = 0; loop < 100; ++loop)
{
// Create an object.
// With the function to make it start. Store the thread in a vector
threads.push_back(new boost::thread(<Function To Call>));
// Add the thread to the group.
group.add(threads.back());
}
// Make sure main does not exit before all the threads have completed.
group.join_all();
}
If we go back to your example and retrofit your Soldier class:
int main()
{
boost::thread batallion;
// Make all the soldiers part of a group.
// When you start the thread make the thread join the group.
Soldier s1(batallion);
Soldier s2(batallion);
Soldier s3(batallion);
s1.start(20);
s2.start(30);
s3.start(40);
// Create 100 soldiers outside the loo
std::vector<Soldier> lotsOfSoldiers;
lotsOfSoldiers.reserve(100); // to prevent reallocation in the loop.
// Because you are using objects we need to
// prevent copying of them after the thread starts.
for (int i = 0; i < 100; ++i)
{
lotsOfSoldiers.push_back(Solder(batallion));
lotsOfSoldiers.back().start(30);
}
// Print out values while threads are still running
// Note you may get here before any thread.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
batallion.join_all();
// Print out values when all threads are finished.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}