2013-10-06 10 views
0

Вопрос 1: Я пытаюсь назвать каждый поток, чтобы его можно было использовать во всей программе, но я получаю такие ошибки, как «запрос для элемента« fid »в« плоскостях [t] » который имеет тип non-class 'pthread_t'. Он ссылается на использование плоскостей [t] .tid или использование плоскостей [t] .startState. Я не уверен, как еще получить/сохранить эти значения для каждого отдельного потока .Как получить доступ к информации о потоке по всей программе

Вопрос 2:., как только у меня есть startState волоска, то как я могу отправить нить функции взлетного() (серию стрелочных состояний и 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 << "'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); 
} 
+0

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

+0

@ Рихард: Вы * не можете *. Для переменной контекста, переданной в 'pthread_create', а затем в процедуру потока, требуется стирание типа. Ну, я смущен, потому что похоже, что у него есть две функции, разработанные как потоковые процедуры, но только один используется таким образом. –

+0

@BenVoigt, StartState(). –

ответ

0

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

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 (int i = 0; i < 100; i++) { 
    // modify the flight data 
    sleep(1000); // sleep for a second (1000 milliseconds) then repeat 
} 

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

Итак, когда вы обернуть 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() выглядела примерно так, и вы использовали бы вид finite state machine для перехода из состояния в состояние, возможно, используя случайное число генератор катиться виртуальные кости с помощью rand() function as in these examples, чтобы определить следующее состояние или оставаться в текущем состоянии:

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() и любая функция, которую она вызывает, больше не должны беспокоиться о других потоках, поэтому все эти петли с NUM_THREADS в этих функциях не должны быть там.

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

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

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

+0

ваш пост очень помог мне. Я обновил то, что у меня теперь есть, в исходное сообщение. rand() и srand() дали мне трудное время, поэтому я в настоящее время звоню в Start закомментировал, и я использую rand() непосредственно в основном. Теперь ... программа запускается снова (hooray!), Но только потоки 1 и 2, похоже, выходят из основного, и программа запускается и запускается, но больше ничего не происходит. Что-нибудь видишь, чего я не вижу? – Anna

+0

@ Анна, похоже, вы обновили источник. Я собираюсь сделать редактирование, чтобы указать это. В вашем источнике у вас есть петли для NUM_THREADS в нескольких местах, которые вы не должны делать. Единственное место, где вам нужно NUM_THREADS, - это когда вы начинаете потоки. Другие места - это только источник для конкретного потока, и этот источник повторно используется каждым потоком. –

+0

@Anna, обратите внимание, что в моих примерах функция FlyPlaneFlight() не имеет цикла для NUM_THREADS. В вашем коде единственное место, где должен быть цикл с NUM_THREADS, - это когда вы запускаете различные потоки. Другие функции работают на полете одновременно и не знают ничего, кроме полета, над которым они работают. Было бы лучше всего написать это для одного полета сначала, используя подход, как я предоставляю. –

Смежные вопросы