Вопрос 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);
}
Похоже, что вы путаете переменную управления 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(), заключается в предоставлении серии изменений состояния для конечного автомата для конкретного полета. Другими словами, что внутри циклы - это самолетный полет.
Посмотрите на разницу между предложенным циклом создания потока и вашим. Шахта делает не что иное, как создание потоков. Вы создаете потоки, а затем пытаетесь сделать что-то с элементом массива полетов, который действительно должен теперь принадлежать нити, созданной, а не основной.
Все эти переменные, по-видимому, хранятся в массиве flights
, а не в массиве planes
.