2017-06-30 48 views
0

我想使用pthread來實現一個線程類。 當然,我想爲我創建的每個線程設置不同的啓動例程。 pthread_create tho只允許一個靜態函數作爲啓動例程,所以它不能被實例化。 有沒有辦法讓這個或更好地使用一個結構來處理我的線程? 這是我SOFAR寫的代碼:Posix線程類和啓動例程(pthread)

class thread { 

    string name; 
    pthread_t id; 
    pthread_mutex_t mutex; 
    pthread_cond_t cond; 
    pthread_attr_t attr; 

public: 
    thread (string t_name); 

static void* start(void*); 

int id_get(); 


private: 

}; 

thread::thread (string t_name) 
{ 

    name = t_name; 
    pthread_attr_init(&attr); 
    int stacksize = sizeof(double) * TH_STACK_SIZE * 30; 
    pthread_attr_setstacksize(&attr, stacksize); 
    int rc = pthread_create (&id, &attr, &start, NULL); 

    cout << "return_code: " << rc << endl; 
    cout << id; 


} 
void* thread::start(void*) 
    { 
while(1){ 
cout << "here"; 
pthread_exit(NULL); 
    } 
    } 

int thread::id_get() 
{ 
    return id; 

} 

和我的測試主要:

int main(void) { 
    cout << "Creating threads" << endl; 
    thread test1("first"); 
    thread test2("second"); 

    pthread_join(test1.id_get(),NULL); 
    pthread_join(test2.id_get(),NULL); 

    return 0; 

} 
+3

爲什麼不使用現有的std ::線程? –

+0

原因我正在交叉編譯ARM,看起來像pthread更便攜(至少這是我讀到的)。 – Podarce

+0

std代表什麼? –

回答

1

我想爲每個線程我有 創建不同的啓動例程。

當我使用posix線程時(我現在使用std :: thread),我使用了'兩步'入口機制。在這兩個步驟的(小)成本下,每個班級都可以輕鬆擁有自己的線程。

我總是保持這些入口方法是私人的。

class Foo_t 
{ 

    // ... etc 

private: 
    static void* threadEntry(void* ptr); 

    void* threadEntry2(void); // thread actions in an object method 

    // ... etc 
} 

因爲這些都是私人的,類有一些公共的方法來創建POSIX線程,通常是這樣的:

void Foo_t::startApp() 
{ 
    // ... etc 

    int pcStat = m_Thread.create(Foo_t::threadEntry, this); 
    // this 2 parameter method of my thread wrapper class 
    // invoked the 4 parameter "::pthread_create(...)". 
    // The 'this' param is passed into the 4th parameter, called arg. 
    dtbAssert(0 == pcStat)(m_nodeId)(pcStat)(errno); 

    // ... 
} 

注意第二個參數,「這」,以m_Thread.create() 。

該線程將開始在靜態方法:

void* Foo_t::threadEntry(void* a_ptr) 
{ 
    dtbAssert(a_ptr != 0); 

    Foo_t* a_foo = static_cast<Foo_t*>(a_ptr); 

    void* retVal = a_foo->threadEntry2(); 

    return(retVal); 

}

這裏,void *的參數與類實例的this指針填寫,然後的static_cast回我們需要的是一個Foo_t *。記住,這個方法是私有的,所以只有startApp()會創建一個線程。

注意threadEntry()調用稱爲類實例的實際方法:

void* Foo_t::threadEntry2(void) 
{ 
    DBG("Thread %2d (id=%lx): sems %p/%p, " 
     "Entering sem controlled critical region\n", ...); 

    // ... start thread work 

} 

,從這裏,實例的任何方法可用。


那麼,接下來呢。有很多方法可以進入不同的線程例程。

考慮加入一個參數的startApp:

void Foo_t::startApp(int select); 

的 '廉政選擇' 和一個開關/ case語句可以運行一個獨特的threadEntry()。

也許可以安裝'int select'(在實例中),以便threadEntry()中稍後的開關/例程可以運行唯一方法或threadEntry2_x()。

也許開關/外殼可能安裝在threadEntry2()中。

請考慮startApp參數可能是一個方法指針。

void Foo_t::startApp(<method pointer>); 

方法指針可以(更直接地)調用,而不是'固定'名稱threadEntry2()。

以上是小問題。

互斥並且在一個實例中運行多個線程是更大的問題。

我確實在單個類實例中有多個線程'運行'。爲此,我使用了關鍵部分,在互斥體或其他防護機制下。 std :: mutex很方便,可以和'Posix'線程一起工作,但在Ubuntu上,我經常使用Posix進程信號量,設置爲本地模式(未命名,未共享)。 PPLSem_t是高效的,適用於包裝在一個小類中的4行方法。


在pthread_create壽只允許一個靜態函數作爲起動程序, 所以它不能被實例化。

實例化包含靜態方法的類的實例並沒有困難。我不確定你在這個陳述/背景中的含義。

查看我上面詳細介紹的方法,並且您應該快速地在您的類實例中運行Posix線程。


記住要檢查堆棧使用和多少RAM,可用您的ARM系統上。 Ubuntu默認堆棧大小爲8 MB。也許你的ARM提供堆棧大小控制。

+0

有一個POSIX例程來獲取堆棧大小「int stat = pthread_attr_getstacksize(&tattr,&size);」,它運行的線程是 –

+0

它發生在我身上,你可能試圖讓一個線程創建它可以在其中運行的類實例運行。pthread_create()_can_調用一個函數(即不是一個方法),這個函數不需要成爲某個類的靜態方法。運行該函數的線程可以實例化類實例,並通過public方法可能,但我更喜歡這個實例來啓動一個'私人'線程。 –

1

如果你有POSIX線程availble的,std::thread將可用於任何C++編譯器支持目前的標準(由於C++ 11)。所以基本上你不需要爲你的交叉編譯目標(例如GCC自4.9版左右開始支持)推出你自己的thread類。


但總的來說你的方法是正確的。爲了使其適用於各種類,您可以simmply使thread類模板:

template<typename T> 
class thread { 

    string name; 
    pthread_t id; 
    pthread_mutex_t mutex; 
    pthread_cond_t cond; 
    pthread_attr_t attr; 

public: 
    thread (string t_name, T& runnable); 

    static void* start(void*); 

    int id_get(); 
    T& runnable_; 
}; 

和落實構造和start()功能如下:

template<typename T> 
thread<T>::thread (string t_name) 
: name(t_name) 
, runnable_(runnable) 
{  
    pthread_attr_init(&attr); 
    int stacksize = sizeof(double) * TH_STACK_SIZE * 30; 
    pthread_attr_setstacksize(&attr, stacksize); 
    int rc = pthread_create (&id, &attr, &start, this); 
              // ^^^^ 

    cout << "return_code: " << rc << endl; 
    cout << id; 
} 

template<typename T> 
void* thread<T>::start(void* pThis) { 
    thread<T>* realThis = reinterpret_cast<thread<T>*>(pThis); 
    (realThis->runnable)_.start(); 
    pthread_exit(NULL); 
} 

thread類可再使用像如下:

struct MyRunnable { 
    MyRunnable(/* Whatever parameters needed */) 
    : /* Whatever needs to be initialized */ { 
    } 
    void start() { 
     /* Full access to all class member variables */ 
    } 
} 

int main() { 
    MyRunnable run(/* Whatever parameters needed */); 
    thread<MyRunnable> t("TheTreadName",run); // start() will execute here 
    // do concurrent stuff 
    t.join(); 
} 

我只是會選擇不同的名稱作爲thread以避免任何cla與C++標準庫一起工作。