c++ - 如何在整个程序中访问有关线程的信息

标签 c++ c multithreading

问题1:我试图命名每个线程,以便可以在整个程序中使用它,但是却收到诸如“请求在'planes [t]'中的成员'fid',这是非类类型'pthread_t'的错误。指的是使用planes [t] .tid或使用planes [t] .startState。我不确定如何为每个单独的线程获取/保存这些值。

问题2:一旦有了线程的startState,如何将线程发送到takeoff()函数(一系列开关状态和printfs)。

问题3:应将什么传递给StartState函数?我试图让每个线程记住其启动状态,以便稍后在代码中可以使飞行“着陆”或“起飞”。

这是相关的代码:在22:37更新10/06

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

最佳答案

看来您正在将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 ()并向其传递一个Flight变量,然后该函数调用其他函数执行各种操作,当Flight结束时,它返回给调用者,您可能会处在一个好地方对于线程。在为单个飞行准备好逻辑之后,您可以使用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()函数包装到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
    }
}


根据源更新10/06在22:37编辑#2

在您的源代码中,您有一个全局数组变量flights,您正尝试直接通过源代码进行访问。这是一个导致您陷入困境的错误。您需要做的是让您的线程create调用将特定的Flight数组元素分配给特定线程。然后,此时您不必担心flight数组,而只需要处理分配给该线程的特定元素即可。

例如,使用如下创建线程,该线程创建线程并将唯一的数组元素分配给要创建的线程。

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()中产生循环的原因是为特定飞行的有限状态机提供一系列状态更改。换句话说,回路内部是飞机飞行。

看一下我建议的线程创建循环和您的线程创建循环之间的区别。我的无非就是创建线程。您创建了线程,然后尝试使用flights数组元素执行操作,该元素现在实际上应该属于创建的线程而不是主线程。

关于c++ - 如何在整个程序中访问有关线程的信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19204723/

相关文章:

multithreading - WinForms 线程安全控件

c++ - 使用 -O3 在 GCC 中编译共享库不会导出与 -O0 一样多的符号

c++模板类型推导在强制转换运算符中失败

c++ - 编译器之间的浮点不匹配(Visual Studio 2010 和 GCC)

c - 带有 MinGW-w64 的 strerror

计算两个日期之间的天数,但结果是错误的

c# - UI 线程正在阻止调用 COM 对象的后台线程

c++ - 我如何使用 boost::thread::id 作为 unordered_map 的键?

c++ - 混合 C/C++ 库

比较 C 中数组的内容