Anna
Anna

Reputation: 3

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

Upvotes: 0

Views: 218

Answers (2)

Richard Chambers
Richard Chambers

Reputation: 17593

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.

Upvotes: 1

Ben Voigt
Ben Voigt

Reputation: 283694

All those variables appear to be stored in the flights array, not the planes array.

Upvotes: 0

Related Questions