Как получить экземпляр объекта, связанного с потоком в C ++? - PullRequest
1 голос
/ 19 августа 2009

В Java у меня есть следующий сгенерированный код:

public class B {
    public void exec(){
        X x = (X) Thread.currentThread();
        System.out.println(x.value);
    }
}

public class X extends Thread{
    public int value;

    public X(int x){
        value = x;
    }
    public void run(){
        B b = new B();
        b.exec();
    }
}

new X(4).start();

Метод B exec () извлекает значение поля, соответствующее текущему потоку (также экземпляру класса X).

Есть ли способ симулировать такое же поведение в C ++? Примечание: я не хотел бы передавать x в качестве параметра экземпляру B, потому что код сгенерирован.

class B {
public:
    void exec();
};

class X {
public:
    int value;
    X(int x) {
        value = x;
    }
    void run() {
        B * b = new B();
        b->exec();
    }    
};

void B::exec() {
    std::cout << ??? << std::endl;
}

int main() {
    X * x = new X(3);
    boost::thread thr(boost::bind(&X::run, x));
    thr.join();
}

Я не знаю, как получить экземпляр класса, связанный с потоком (я знаю, у меня его нет), есть идеи?

Ответы [ 2 ]

4 голосов
/ 19 августа 2009

Если вы не хотите передавать параметры в B (что было бы самым чистым решением), вы можете использовать локальное хранилище потока.

Хотя, глядя на ваш код в целом, вы, вероятно, будете стрелять себе в ногу, попробовав это строгое отображение 1-к-1 с Java на C ++.

В C ++ вы почти никогда не должны вызывать new. Выделите в стеке, когда это возможно. new в C ++ явно подвержен ошибкам (без сборки мусора), но он также чрезвычайно медленный по сравнению с управляемыми языками, такими как Java.

Функторы можно использовать в качестве более мощной альтернативы указателям на функции (например, при создании потока) или просто для замены общих функций exec() или run(). Вместо этого назовите их operator(), и класс можно использовать как функтор.

И в ваших конструкторах вы должны как можно больше использовать список инициализаторов.

Следующие рекомендации применимы к вашему коду. Конечно, я передал аргумент в конструктор B. Если это не вариант, используйте локальное хранилище потока .

class B {
public:
    explicit B(int value) : value(value)
    void operator()();

private:
    int value;
};

class X {
public:
    int value;
    X(int x) :value(x) { }// use the initializer list to initialize members

    void operator()() {
        B b(value); // allocate B on the stack if possible
        b();
    }    
};

void B::operator()() {
    std::cout << value << std::endl;
}

int main() {
    boost::thread thr(X(3));
    thr.join();
}

Конечно, в этом простом примере вам не нужны два класса. С таким же успехом вы могли бы полностью удалить X и сделать:

class B {
public:
    explicit B(int value) : value(value)
    void operator()();

private:
    int value;
};

void B::operator()() {
    std::cout << value << std::endl;
}

int main() {
    boost::thread thr(B(3));
    thr.join();
}
2 голосов
/ 19 августа 2009

Это правда, что вы не можете (или не должны) подкласс boost::thread. Вы можете использовать локальное хранилище потоков , чтобы разместить свои собственные специфичные для потока вещи.

Возможно, вы должны использовать ту же технику для кода Java. Для этой цели Java имеет ThreadLocal.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...