2009-01-11 4 views
3

У меня есть вопрос относительно этого кода, который я хочу работать на QNX:QNX C++ нить вопрос

class ConcreteThread : public Thread 
{ 
public: 
    ConcreteThread(int test) 
    { 
     testNumber = test; 
    } 

    void *start_routine() 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      sleep(1); 
      cout << testNumber << endl; 
     } 
    } 

private: 
    int testNumber; 
}; 




class Thread 
{ 
public: 
    Thread(){}; 

    int Create() 
    { 
     pthread_t m_id; 
     return pthread_create(&m_id, NULL, &(this->start_routine_trampoline), this); 
    } 

protected: 
    virtual void *start_routine() = 0; 

private: 

    static void *start_routine_trampoline(void *p) 
    { 
     Thread *pThis = (Thread *)p; 
     return pThis->start_routine(); 
    } 
}; 

Теперь, когда я запускаю этот код без сна в * start_routine, он будет просто печатать номер 10 раз, прежде чем перейти к следующей строке кода (последовательно, а не параллельно). Однако, когда я использую сон, как в коде, он вообще не печатает никаких чисел и просто переходит к следующей строке кода. Почему не работает со сном и как я могу сделать поток, подобный этой работе, вместо того, чтобы работать последовательно?

ответ

4

Примечание 1: Если у вас только 1 процессор, код может выполняться последовательно, независимо от того, сколько потоков вы создаете. Каждому потоку присваивается кусочек процессорного времени, прежде чем он будет заменен для следующих потоков.

Примечание 2: Если основной поток выходит из pthreads, он убьет все дочерние потоки, прежде чем они смогут выполнить.

Теперь, чтобы ответить вам вопросы:

без сна. Однажды начатая нить имеет достаточно времени в единственном фрагменте, который ему давался, чтобы выполнить цикл 10 раз полностью.

С сон: Ваша рабочая нить будет спать на полную секунду. Таким образом, ваш основной поток успевает сделать много работы. Если основной поток выйдет за это время, рабочий будет убит.

Я хотел бы сделать следующие изменения:

// Remove the Create() method 
// Put thread creation in the constructor. 
// Make the thread variable part of the object 

pthread_t m_id; 

Thread() 
{ 
    if (pthread_create(&m_id, NULL, &(this->start_routine_trampoline), this) != 0) 
    { 
     throw std::runtime_error("Thread was not created"); 
    } 
} 

// Make sure the destructor waits for the thread to exit. 
~Thread() 
{ 
    pthread_join(m_id); 
} 

Если вы идете и смотрите на повышения многопотоковости библиотеки. вы обнаружите, что все маленькие ошибки, подобные этому, уже позаботились; Таким образом, упрощение использования резьбы.

Также обратите внимание. То, что использование статики может работать, но не переносимо. Это связано с тем, что pthread является C-библиотекой и, следовательно, ожидает указатель на функцию с C ABI. Вам просто повезло с вашей платформой здесь. Вы должны определить это как функция и объявить ABI помощью Экстерн «C»

// This needs to be a standard function with C Interface. 
extern "C" void *start_routine_trampoline(void *p) 
{ 
} 
+0

+1 за правильный ответ. Но я НЕ так уверен в * «избегая использования статических методов в качестве функции pthread» *. См. Http://stackoverflow.com/questions/433220/qnx-c-thread-question#433614 –

+0

См. Комментарии в своем ответе. Он указывает на статью по адресу http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2, что в секундах мое мнение. –

3

Попробуйте сделать pthread_t идентификатор класса члена вместо локальной переменной функции. Таким образом, вызывающий может pthread_join.

Не делать это технически является утечкой ресурсов (если только поток специально не соединяется). И соединение позволит избежать проблемы, описанной Martin York.

от человека pthread_join:

соединенной нити й должен находиться в подключаемом состоянии: оно не должно быть отсоединен с помощью pthread_detach (3) или PTHREAD_CREATE_DETACHED атрибут pthread_create (3).

Когда соединительная нить завершается, ее ресурсы памяти (поток дескриптор и стек) не освобождаются до тех пор, пока другой поток не выполнит pthread_join. Следовательно, pthread_join необходимо вызывать один раз для каждого связанного потока, созданного для предотвращения утечек памяти.

+0

Мне обычно проще просто отсоединить и синхронизировать семафоры. –

0

Отключение по касательной здесь ...Что касается Martin York's post:

Также обратите внимание. То, что использование статики может работать, но не переносимо. Это связано с тем, что pthread является C-библиотекой и, следовательно, ожидает указатель на функцию с C ABI. Вам просто повезло с вашей платформой здесь. Вы должны определить это как функцию и объявить ABI с помощью extern «C»

// Это должна быть стандартная функция с интерфейсом C.
ехЬегп "C" недействительным * start_routine_trampoline (пустота * р) {...}

Я не уверен, что ...

(1) C++ был разработан, чтобы быть совместимый с C. There are a few differences... Но у меня создалось впечатление, что extern «C»   использовался в основном для обхода имени, требуемого для реализации перегрузки функций C++.

(2) Кажется, что после того, как у вас есть указатель на функцию, вызывающие соглашения (то, что нажимается на стек для вызова функции) должны быть одинаковыми между C & C++. В противном случае, как будут работать функции указателей?

т.д .:

код C:

void bar(int i) { printf("bar %d\n", i); } 

C++ код:

class Foo 
{ 
public: 
    static void foo(int i) { cout << "foo " << i << endl; } 
}; 

extern "C" { void bar(int); } 

int main() 
{ 
    void (*p)(int); 

    p = & Foo::foo; 
    (*p)(1); 

    p = & bar; 
    (*p)(2); 
} 
+0

Статические функции класса не имеют клиентов на вызовах, они обычно реализуются таким образом, который совместим с соглашением C: см. Http://www.parashift.com/c++-faq-lite/pointers-to-members. html # faq-33.2 и прочитайте примечание внизу. –

+0

Увлекательный. Поэтому было бы законным, если бы компилятор имел дополнительное хранилище, прикрепленное к указателям на функции, чтобы указать, указали ли они на функцию C vs C++. –

+0

Глупый, увеличивает sizeof (p), снижает совместимость C/C++, добавляет нежелательную боль в кодирование и т. Д. Но это законно. Благодаря! И спасибо за ссылку! Это хорошо знать! –