How to access info about a thread throughout a program - c++

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.

Related

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.

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

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.

naming threads, using typedef/struct

I am creating a program to practice using threads. I am trying to name them so that when the program is run, you can clearly see "Flight 1 is taking off..." or "Flight 6 is landing..." and so on. I would like every thread to have a flyTime (so I know what order they will use the runway in) which will be randomly generated. I have tried and am having difficulty using struct/typedef to give each pthread these characteristics so i can say for example flight.flyTime and use it throughout the program. Here is the relevant part of my code without my landing/takeoff functions:
#include <pthread.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <queue>
#define NUM_THREADS 8 //8 flights
pthread_mutex_t runway1lock;
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
pthread_exit(NULL);
}
typedef struct{ //each plane has these characteristics
long fid;
int StartState; // if start=1 ==> taking off:::if start=2 ==> landing
int flyTime; //fly == randomly generated time (order)
}FLIGHTS;
FLIGHTS flights[NUM_THREADS];
int StartState(flights[NUM_THREADS]){
int startState;
for (int i=0; i<=NUM_THREADS; i++){
startState = rand() % 1+2;
}
std::string start;
if(startState == 1){
start = "Taking off";
}
if(startState == 2){
start = "Landing";
}
for (int t=0; t<NUM_THREADS; t++){
std::cout << "Start State for Flight# " << FlightID << " is " << start << std::endl;
}
return startState;
}
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 rc;
long t;
for (t=1; t<=NUM_THREADS; t++){ //loop creates threads(flights)
printf("In main: Creating flight %1d\n", t);
rc = pthread_create(&flights[t], NULL, FlightID, (void *)t);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
StartState(flights[t]); //gives every flight a start state
if(StartState(flights[t])==1){
std::cout << "Flight # " << &flights[t] << " is listed as waiting at the gate." << std::endl;
//go to takeoff function and go through switch case
}
if(StartState(flights[t])==2){`enter code here`
std::cout << "Flight # " << &flights[t] << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
}
pthread_exit(NULL);
}
There is a code snippet below that represents how I would implement it.
You should also take a look at pthread_key_create, pthread_getspecific and pthread_setspecific. This is a set of functions that allow you to have data, specific to each thread, stored in the thread's memory context. It may come in handy for in your code, later on.
typedef struct{
long fid;
int StartState;
int flyTime;
} FLIGHTS;
FLIGHTS** flights = new FLIGHTS*[NUM_THREADS];
pthread_key_t pkey:
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
FLIGHTS* flight = new FLIGHTS();
flight->fid = fid;
flights[fid] = flight;
pthread_setspecific(pkey, flight);
int startState;
for (int i=0; i<=NUM_THREADS; i++){
startState = rand() % 1+2;
}
std::string start;
if(startState == 1){
start = "Taking off";
}
if(startState == 2){
start = "Landing";
}
for (int t=0; t<NUM_THREADS; t++){
std::cout << "Start State for Flight# " << fid << " is " << start << std::endl;
}
flight->StartState = startState;
}
int main(int argc, char* argv[]) {
pthread_key_create(&pkey, NULL);
for (t=1; t<=NUM_THREADS; t++){
rc = pthread_create(&flights[t], NULL, FlightID, (void *)t);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
}
}
Also, I don't know if I'm understanding your code correctly or if you just have some coding errors on it, so I leave you with some questions or remarks that could be mistakes/bugs:
1) You invoke pthread_exit in the start callback function:
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
pthread_exit(NULL);
}
2) You pass to the << operator a function with no return value:
std::cout << "Start State for Flight# " << FlightID << " is " << start << std::endl;
3) You invoke the same function 3 times just to get the return value. Shouldn't it be int state = StartState(flights[i]) and then test the state variable value?
StartState(flights[t]); //gives every flight a start state
if(StartState(flights[t])==1){
std::cout << "Flight # " << &flights[t] << " is listed as waiting at the gate." << std::endl;
//go to takeoff function and go through switch case
}
if(StartState(flights[t])==2){`enter code here`
std::cout << "Flight # " << &flights[t] << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
4) You can't define a function like this:
int StartState(flights[NUM_THREADS]){

binary semaphore to synchronize threads in c++

everyone.
I am new to semaphore and recently I am learning to implement a simple problem using binary semaphores and i have some questions.
So there is a visiting room, at one time only one person can go in. In my design there are three queues of people (which are all the threads i created). For example, after the person in the second queue visited that room, the next person who is going to enter the room is the top one waiting in third queue, rather the first queue's person. The number of total people is given. and after leaving, just simply terminate the thread.
I am trying to create three semaphores to handle this, i.e, after one person in second queue enters, then block the second queue and ONLY "signal" the third queue to continue. and so on so forth. However, the code has some problems. here I just show some semaphore part of code.
int the main:
sem_init(&mutex, 0, 1);
sem_init(&s0, 0, 1);
sem_init(&s1, 0, 1);
sem_init(&s2, 0, 1);
// create 100 pthread and randomly put into queue0 or queue1 or queue2
for(int i = 0; i<num_thread; i++){
pthread_t curr_thread;
if(queueId == 0){
queue0.push(curr_thread);
}else if(queueId == 1){
queue1.push(curr_thread);
}else if(queueId == 2){
queue2.push(curr_thread);
}
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create (&curr_thread, &attr, &thread_function, &queue_Num);
pthread_attr_destroy (&attr);
}
in the thread function:
void* thread_function (void* arg){
sem_wait(&mutex);
int n = *((int*) arg);
if(n==0){
sem_wait(&s0);
cout << "person in queue" << n << " is visiting" << endl;
sleep(1);
if(!queue0.empty()){
queue0.pop();
}else{
n++;
}
sem_post(&s1);
}else if(n==1){
sem_wait(&s1);
cout << "person in queue" << n << " is visiting" << endl;
sleep(1);
if(!queue1.empty()){
queue1.pop();
}else{
n++;
}
sem_post(&s2);
}else if(n==2){
sem_wait(&s2);
cout << "person in queue" << n << " is visiting" << endl;
sleep(1);
if(!queue2.empty()){
queue2.pop();
}else{
n++;
}
sem_post(&s0);
}
sem_post(&mutex);
return NULL;
}
Actually when I run it, seems like I met "deadlock", the main finished with showing only 2 threads every time. I thought there must be some problems in the designing of the thread_function. Is there anybody can help point it out and tell me how to fix it? Thanks advance.
When you pass your queueId to the threads, you don't want to pass it a pointer to one of your local variables, because you are going to be changing that very quickly. You should instead just be passing in the integer itself to your threads:
pthread_create(&curr_thread, &attr, &thread_function, (void*)queueId);
// Pass queueId the int, not a pointer
Then, when you need to read the value in your threads, just cast the void* back to an integer:
void* thread_function (void* arg){
...
int n = (long)arg;
..
}
After this, your code works great, for me.

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';
}