Pthread_getspecific值更改/导致错误

时间:2016-10-30 06:42:18

标签: c++ pointers pthreads

目前代码似乎运行正常,直到最后一次被要求getspecific。我认为它可能只是在一次使用后破坏,因为关于神秘(对我而言)pthread_once的讨论似乎意味着,但是通过一个简单的cout陈述,我能够让它再次得到它。 (把它留在这里的代码中)

它的工作原理(阅读:没有故障),但它给我一个与前一次调用不同的值(第一次调用打印线程的ID,第二次打印ID + 1)

我一直在玩它并在谷歌上搜索一段时间,但我似乎无法在这个问题上找到任何东西。希望我能再次错过一些明显的东西。

相关代码在person方法中。谢谢你的帮助!

#include <pthread.h>
#include <iostream>
#include <stdlib.h>
#include <semaphore.h>

using namespace std;

sem_t lobby_people;         //current number of people in the "lobby"
sem_t rider;                //people on the elevator
sem_t ele_full;             //tells the elevator it is full
sem_t arrived;              //tells elevator the person got off, prevents closing the door before they leave
sem_t sim_done;             //tells main that elevator is done
sem_t initialized;          //tells main that person has recorded their pid from guest so that it can be safely incremented
sem_t exiting_on[11];       //holds persons until they reach their desired floor
int pushed_button[11] = {0}; //craftily allows elevator to know how many people want to go to a floor
int e_capacity = 7;         //craftily allows people to know when to tell elevator to close
pthread_key_t ID_key;
pthread_key_t target_key;

void board(int person_number, int target_floor)
{
    cout << "Person "<< person_number << " enters elevator to go to floor " << target_floor <<endl;
}

void get_off(int person_number)
{
    cout << "Person "<< person_number << " leaves elevator" << endl;
}
void close_door()
{
    cout << "Elevator door closes" << endl;
}
void open_door(int floor)
{
    cout << "Elevator door opens at floor " << floor << endl;
}
void complete()
{
    cout << "Simulation done" << endl;
}

void *person(void *pid)
{
    int* person_number = static_cast<int*>(pid);
    int* target_floor = new int;
    (*target_floor) = rand() % 10 + 2;
    pthread_key_create(&ID_key, NULL);
    pthread_key_create(&target_key, NULL);
    pthread_setspecific(ID_key, (void*)person_number);
    pthread_setspecific(target_key, (void*)target_floor);
    sem_post(&initialized);
    sem_wait(&rider);
    board(*static_cast<int*>(pthread_getspecific(ID_key)), *static_cast<int*>(pthread_getspecific(target_key))+1);
    cout<<*static_cast<int*>(pthread_getspecific(ID_key))<<endl;                    //for testing
    sem_wait(&lobby_people);
    e_capacity--;   
    pushed_button[(*static_cast<int*>(pthread_getspecific(target_key))) + 1]++;
    if(e_capacity==0)
        sem_post(&ele_full);
    sem_wait(&exiting_on[(*static_cast<int*>(pthread_getspecific(target_key))) + 1]);
    get_off(*static_cast<int*>(pthread_getspecific(ID_key)));                       //apparent culprit here!
    sem_post(&arrived);
    pthread_exit(NULL);
}

void *elevator(void *arg)
{
    for(int trips = 0; trips < 7; trips++)
    {
        sem_wait(&ele_full);
        close_door();
        for(int current_floor = 1; current_floor < 11; current_floor++)
        {
            if(pushed_button[current_floor] != 0)
            {
                open_door(current_floor);
                while(pushed_button[current_floor] > 0)
                {
                    pushed_button[current_floor]--;
                    sem_post(&exiting_on[current_floor]);
                    sem_wait(&arrived);
                }
                close_door();
            }   
        }
        open_door(1);
        e_capacity = 7;
        for(int new_riders = 0; new_riders < 7; new_riders++)
            sem_post(&rider);   
    }
    sem_post(&sim_done);
    pthread_exit(NULL);
}

int main()
{
                                                        //initializing our semaphores
    sem_init(&lobby_people, 0, 0);
    sem_init(&rider, 0, 7);
    sem_init(&ele_full, 0, 0);
    sem_init(&arrived, 0, 0);
    sem_init(&sim_done, 0, 0);
    sem_init(&initialized, 0, 0);

    for(int x = 0; x<11; x++)
        sem_init(&exiting_on[x], 0, 0);

    pthread_t my_thread;
    pthread_create(&my_thread, NULL, &elevator, NULL); //starts elevator thread, which waits for riders

    for(int guests = 0; guests < 49; guests++)          //generates 49 people threads
    {
        sem_post(&lobby_people);
        pthread_create(&my_thread, NULL, &person, &guests);
        sem_wait(&initialized);                             //waits for the person to copy their value of guests before incrementing it
    }
    sem_wait(&sim_done);                                //awaits the end of the elevator's 7th run
    complete();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

创建person个主题时,会将指针传递给guests

pthread_create(&my_thread, NULL, &person, &guests);

有两个问题:第一个是所有线程都获得相同的指针,因此将使用相同的值。第二个问题是变量guests的范围仅限于循环 。一旦循环结束,变量超出范围,并且所有线程中的指针都无效,您将有未定义的行为

&#34;简单&#34;解决方案是使用the C++ std::thread class代替并按值传递值。

如果要继续使用C和POSIX函数,另一种解决方案是传递变量的。这需要一些演员阵容:

pthread_create(&my_thread, NULL, &person, (void *) (intptr_t) guests);

在线程函数中:

int person = (int) (intptr_t) pid;