3

我有一个关于我想在 QNX 上运行的代码的问题:

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 次,然后继续执行下一行代码(顺序而不是并行)。但是,当我在代码中使用 sleep 时,它根本不会打印任何数字,而是继续执行下一行代码。为什么睡眠不起作用,我怎样才能使这样的线程工作,而不是按顺序运行?

4

3 回答 3

4

注意 1:如果您只有 1 个处理器,则无论您创建多少线程,代码都只能按顺序完成。在为下一个线程换出之前,每个线程都会被分配一段处理器时间。

注意 2:如果主线程退出,pthreads 将在所有子线程有机会执行之前将其杀死。

现在来回答你的问题:

没有睡眠。线程一旦启动,在单个切片中就有足够的时间完全执行循环 10 次。

随着睡眠:您的工作线程将睡眠整整一秒钟。所以你的主线程有时间做很多工作。如果此时主线程退出,worker 将被杀死。

我将进行以下更改:

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

如果你去看看boost 线程库。你会发现像这样的小错误都已经被处理好了;从而使线程更易于使用。

还要注意。使用静态可能有效,但它是不可移植的。这是因为 pthread 是一个 C 库,因此需要一个带有 C ABI 的函数指针。您在这里为您的平台感到幸运。您需要将其定义为函数并使用 extern "C" 声明 ABI

// This needs to be a standard function with C Interface.
extern "C" void *start_routine_trampoline(void *p)
{
}
于 2009-01-11T17:35:08.117 回答
3

尝试使 pthread_t id 成为类成员而不是函数局部变量。这样调用者可以 pthread_join 它。

不这样做在技术上是资源泄漏(除非线程特别不可连接)。加入将避免Martin York所描述的问题。

来自 man pthread_join:

加入的线程必须处于可加入状态:它不能使用 pthread_detach(3) 或 pthread_create(3) 的 PTHREAD_CREATE_DETACHED 属性分离。

当一个可连接线程终止时,它的内存资源(线程描述符和堆栈)不会被释放,直到另一个线程对其执行 pthread_join。因此,必须为每个创建的可连接线程调用一次 pthread_join 以避免内存泄漏。

于 2009-01-11T17:44:37.473 回答
0

在这里切线......关于马丁约克的帖子:

还要注意。使用静态可能有效,但它是不可移植的。这是因为 pthread 是一个 C 库,因此需要一个带有 C ABI 的函数指针。您在这里为您的平台感到幸运。您需要将其定义为函数并使用 extern "C" 声明 ABI

// 这需要是具有 C 接口的标准函数。
extern "C" void * start_routine_trampoline(void * p) {...}

我不太确定...

(1) C++ 被设计为尽可能与 C 兼容。 有一些区别...... 但我的印象是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);
}
于 2009-01-11T20:23:44.687 回答