LINUX.ORG.RU

Функция класса и потоки


0

0

Как можно создать поток с указанием на функцию которая является элементом класса. Т.е. когда я делаю так:

class A:
{
  ...
  void Init(void *arg);
  ...
};

A::A()
{
  pthread_attr_t tattr;
  pthread_t tid;
  extern void *Init(void *arg);
  void *arg;
  int ret;

  ret = pthread_create(&tid, NULL, Init, arg);
  ret = pthread_attr_init(&tattr);
  ret = pthread_create(&tid, &tattr, Init, arg); 

}

void A::Init(void *arg)
{
   ...
}

то в итоге получаю сообщение о том что имеется необъявленная ссылка на Init.

И сюда же вопрос, можно ли в такую функцию передать что либо отличное от void *arg, типа char *a,int b...

Заранее спасибо!!!
★★★★★

Если функцию Init сделать статической, это как-то повлияет на логику приложения?

anonymous
()

ну все-таки скорее где-то так:

class thread {
public :
    // Must be implemented by real client
    virtual void *run() = 0;

    int start() {
        int err = pthread_create(&pth_, 0, real_run, this);
        if (err) {
            // Handle failure
        }
    }

private :
    pthread_t pth_;

    static void * real_run(void *arg) {
        thread *t = arg;
        return t->run();
    }
};

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

ps: если псевдокод не помогает, внизу рабочий пример

--- cut ---

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

class base_thread {
public :
    virtual ~base_thread() {}

    // Must be implemented by real client
    virtual void *run() = 0;

    int start() {
        return ::pthread_create(&pth_, 0, real_run, this);
    }

    pthread_t id() const {
        return pth_;
    }

private :
    pthread_t pth_;

    static void * real_run(void *arg) {
        base_thread *t = static_cast<base_thread *>(arg);
        return t->run();
    }
};

class my_thread : public base_thread {
public :
    void *run() {
        std::cout << "Run my thread!" << std::endl;
        return 0;
    }
};

int
main(int argc, char *argv[])
{
    my_thread t;

    std::cout << "Start thread" << std::endl;
    t.start();
    ::pthread_join(t.id(), 0);
    std::cout << "Done thread" << std::endl;

    return 0;
}
--- cut ---

foo@ip-230$ g++ -Wall -o foo foo.cc -lpthread
foo@ip-230$ ./foo
Start thread
Run my thread!
Done thread

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

А можно пояснить сокральный смысл вызова вот этой функции?!

   ::pthread_join(t.id(), 0);

и два двоеточия в начале это опечатка или то же имеет смысл?

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

> А можно пояснить сокральный смысл вызова вот этой функции?!
>   ::pthread_join(t.id(), 0);

основной поток породил дочерний и ему как-то нужно дождаться его
завершения перед тем, как завершить процесс. pthread_join() делает
то самое aka завершения потока с указанным идентификатором.

http://www.opengroup.org/onlinepubs/009695399/functions/pthread_join.html

> и два двоеточия в начале это опечатка или то же имеет смысл?

ну почему же опечатка, это явное указание на то, что функция
pthread_join() равно как и pthread_create() находятся в глобальном
пространстве имен бо в общем случае они могут быть перекрыты методами
класса, using namespace или еще какой херней. например:

--- cut ---
#include <iostream>

void
fnc()
{
    std::cout << "Global fnc" << std::endl;
}

class foo {
public :
    void fnc() {
        std::cout << "Class fnc" << std::endl;
    }
    void test() {
        fnc();
        ::fnc();
    }
};

int
main(int argc, char *argv[])
{
    foo f;
    f.test();
    return 0;
}
--- cut ---

foo@ip-230$ g++ -Wall -o foo foo.cc
Press any key to continue...
foo@ip-230$ ./foo
Class fnc
Global fnc

называется "почувствуй разницу". как следствие, если вы явным образом
обращаетесь к функции из глобального пространства имен, это лучше
всего не забывать указывать через пустое имя "::". иначе могут быть
проблемы.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

Спасибо, мне тоже было интересно почитать =)

wieker ★★
()
Ответ на: комментарий от cyclon

ну возьмите да засуньте, в чем проблемы? никто не запрещает. только все-таки в base_thread а не my_thread бо последний нужен лишь для того, чтобы реализовать метод абстрактный run(). ну например:

--- cut ---
class base_thread {
public :
    virtual ~base_thread() {}

    // Must be implemented by real client
    virtual void *run() = 0;

    int start() {
        return ::pthread_create(&pth_, 0, real_run, this);
    }
    void wait() {
        ::pthread_join(pth_, 0);
    }

private :
    pthread_t pth_;

    static void * real_run(void *arg) {
        base_thread *t = static_cast<base_thread *>(arg);
        return t->run();
    }
};
--- cut ---

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

Ну в этом варианте как я понял надо вызывать этот wait самому, а можно что бы это вызывалось из start()

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

пробовал добавить это в start но не прокатывало

    int start() {
        int n = ::pthread_create(&pth_, 0, real_run, this);
        ::pthread_join(pth_, 0);
        return n;
    }

cyclon ★★★★★
() автор топика
Ответ на: комментарий от cyclon

"не прокатывало" - это значит не компилируется чтоль ? =)

повторю предыдущего оратора, pthread_join _усыпляет вызывающий_ поток до тех пор пока не завершится указанный (pth_)

то есть Вы создали дочерний поток и потом усыпили основной, до тех пор, пока не завершится дочерний. оригинально :) зачем тогда второй поток Вам вообще нужен ? :)

ps: кстати - не вздумайте засунуть start() в этом виде в конструктор :)

Eshkin_kot ★★
()
Ответ на: комментарий от Eshkin_kot

не прокатывало, значит, поток не запускался, а прога сразу завершалась...

всё получилось, если исплоьзовать detach вместо join

cyclon ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.