Как получить доступ к информации о потоке в программе

0

Вопрос 1: Я пытаюсь назвать каждый поток, поэтому его можно использовать во всей программе, но я получаю такие ошибки, как "запрос для члена" fid "в" плоскостях [t] ", который относится к классу типа" pthread_t ", не относящемуся к классу. ссылаясь на использование плоскостей [t].tid или использование плоскостей [t].startState. Я не уверен, как еще получить/сохранить эти значения для каждого отдельного потока.

Вопрос 2: как только у меня есть thread startState, как я могу отправить поток функции takeoff() (серия состояний переключателей и printfs).

Вопрос 3: Что нужно передать в функцию StartState? Я пытаюсь, чтобы каждый поток помнил свое начальное состояние, так что позже в коде я могу полет "приземлиться" или "взлететь".

Вот соответствующий код: Обновлено 10/06 в 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 << " 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 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);
}
Теги:
multithreading

2 ответа

1

Похоже, что вы путаете переменную управления pthread_t, planes, с переменной, содержащей данные полета, flights.

Управляющая переменная pthread_t, planes, используется библиотекой pthread, и вы действительно должны использовать ее только в качестве аргумента для вызовов библиотеки pthread, иначе просто оставьте ее в покое и не беспокойтесь об этом. Подумайте о переменных planes в качестве области хранения, которую вы создаете, а затем передаете библиотеке pthread для использования, и тем самым вы передаете право собственности на эту переменную в библиотеку pthread.

Таким образом, первый порядок ведения бизнеса состоит в том, чтобы разделить и различить разницу между управлением pthread и фактическими данными, которые обрабатываются потоками.

У вас есть несколько мест, где вы используете переменную управления pthread, planes, как если бы это переменная данных полета. Это не. Заменить planes на 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     
        }

Этот бит источника в вашей функции StartState() не имеет смысла.

for(int i = 0; i<NUM_THREADS; i++){
        startState = rand() % 1+2;
}
startState = my_flights->startState;

Я предполагаю, что вы хотите установить начальное состояние конкретного полета с некоторым случайным стартовым состоянием. Поэтому я ожидаю, что источник будет выглядеть следующим образом, поскольку я предполагаю, что вы заинтересованы в настройке состояния начала для конкретного полета, и цикл на самом деле ничего не делает, кроме как выполнять генератор случайных чисел NUM_THREADS раз, чтобы цикл был просто заменен на что-то вроде следующего. Однако я не проверил вашу логику по этому вопросу и не верен ли диапазон или что-то еще.

my_flights->startState = rand() % 1+2;

Предлагаемый курс действий

Вы должны думать о потоке как о небольшой программе или приложении. Я предлагаю, чтобы на этом простом примере вы в первую очередь пишете свою логику полета, не беспокоясь о потоках. Поэтому, если вы начнете с функции, скажите FlyPlaneFlight() на которую вы передаете переменную полета, и эта функция затем вызывает другие функции, чтобы делать разные вещи, и когда полет заканчивается, он возвращается к вызывающему, вы, вероятно, будете в хорошем месте для потоков. После того, как логика установлена на один рейс, вы затем используете библиотеку pthread для создания нескольких полетов, инициализируя данные полета, а затем создавая поток, который использует FlyPlaneFlight().

Вам также нужно учитывать время и взаимодействие. Для такого рода моделирования я подозреваю, что вы захотите, чтобы FlyPlaneFlight() имела петлю, в которой были внесены изменения в данные полета, а затем нить будет спать второй или второй. В качестве начального теста используйте цикл for с определенным количеством итераций и затем выйдите из следующего:

for (int i = 0; i < 100; i++) {
    // modify the flight data
    sleep(1000);   // sleep for a second (1000 milliseconds) then repeat
}

Если это становится более сложным, так что полеты не являются независимыми, а должны каким-то образом синхронизироваться, вам нужно будет изучить функции синхронизации потоков библиотеки pthread.

Поэтому, когда вы FlyPlaneFlight() функцию FlyPlaneFlight() функцию pthread_create(), она может выглядеть примерно так:

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

Идея состоит в том, чтобы рассматривать самолетный полет как объект, и все необходимые данные для полета находятся в struct flight_data и что по большей части вы можете игнорировать библиотеку pthread, которая не участвует в фактической симуляции полета, а скорее используется для моделирования многолетних летающих объектов. Таким образом, вы создаете несколько потоков, каждый из которых имеет свои собственные данные полета, а затем использует тот же код для обработки данных полета. Вы делаете немного рандомизации, чтобы все различные полеты имели разные истории, они будут делать разные вещи.

редактировать

Тогда у вашего основного было бы нечто вроде следующего

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

Это создаст ваши различные потоки и позволит им работать. В цикле функции FlyPlaneFlight() вас будет статус распечатывать что-то вроде следующего каждый раз через цикл, чтобы ваша FlyPlaneFlight() выглядела примерно так, и вы использовали бы какой-то конечный автомат для перехода от состояния к возможно, используя генератор случайных чисел для свертывания виртуальных кубиков, используя функцию rand(), как в этих примерах, чтобы определить следующее состояние или остаться в текущем состоянии:

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 на основе исходного обновления 10/06 в 22:37

В вашем источнике у вас есть глобальная переменная массива, flights, которые вы пытаетесь получить непосредственно через свой источник. Это ошибка, которая ведет вас к проблемам. Вам нужно сделать, чтобы ваш поток создавал вызов для выделения определенного элемента массива полетов в конкретный поток. Тогда в этот момент вы не беспокоитесь о полете, но вместо этого работаете только с определенным элементом, назначенным этому потоку.

Например, создайте поток следующим образом, который создает поток и назначает уникальный элемент массива для создаваемого потока.

rc = pthread_create(&planes[t], NULL, FlightID, (void *)&flights[t]);

Функция ввода потока, FlightID() принимает в качестве аргумента указатель на этот элемент массива, поэтому в этот момент любая из ваших функций, которые работают с данными полета на flights[t] может просто использовать этот указатель на этот элемент массива. Функции должны только беспокоиться об их конкретном полете, а не о всех остальных полетах.

Также после запуска потока функция FlightID() и любая FlightID() ею функция больше не должны беспокоиться о других потоках, поэтому все эти циклы с NUM_THREADS в этих функциях не должны быть там.

Идея состоит в том, чтобы иметь небольшую программу, которая запускается при вызове FlightID() который работает на конкретном полете. Затем с несколькими потоками каждая нить начинается с FlightID(). Таким образом, это похоже на идею main() являющуюся точкой входа для программы C/C++, где main() имеет некоторые аргументы, и ваша программа начинается с main(). В случае потоков поток начинается с функции ввода потока, которая в вашем случае - FlightID().

Причина, по которой у меня есть петля в FlyPlaneFlight(), заключается в предоставлении серии изменений состояния для конечного автомата для конкретного полета. Другими словами, что внутри циклы - это самолетный полет.

Посмотрите на разницу между предложенным циклом создания потока и вашим. Шахта делает не что иное, как создание потоков. Вы создаете потоки, а затем пытаетесь сделать что-то с элементом массива полетов, который действительно должен теперь принадлежать нити, созданной, а не основной.

  • 0
    Ваш пост очень помог мне. Я обновил то, что у меня сейчас есть в исходном посте. rand () и srand () доставляли мне неприятности, поэтому в настоящее время я закомментировал вызов Start, и я использую rand () непосредственно в main. Теперь ... программа запускается снова (ура!), Но только потоки 1 и 2, кажется, делают это из main, и программа запускается и работает, но больше ничего не происходит. Вы видите что-то, чего я не вижу?
  • 0
    @ Анна, похоже, ты обновил источник. Я собираюсь сделать правку, чтобы указать это. В вашем источнике у вас есть циклы для NUM_THREADS в нескольких местах, которые вы не должны делать. Единственное место, где вам нужен NUM_THREADS - это когда вы запускаете потоки. Другие места являются просто источником для определенного потока, и этот источник повторно используется каждым потоком.
Показать ещё 1 комментарий
0

Все эти переменные, по-видимому, хранятся в массиве flights, а не в массиве planes.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню