[英]Posix Thread Class and Start Routines (pthread)
我想使用pthread實現線程類。 當然,我要為正在創建的每個線程使用不同的啟動例程。 pthread_create tho只允許將靜態函數作為啟動例程,因此無法實例化。 有沒有辦法允許使用它,還是使用結構來處理我的線程更好? 這是我寫的sofer的代碼:
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;
}
如果您有POSIX線程可用,則std::thread
將可用於支持當前標准的所有C ++編譯器(自c ++ 11起)。
因此,基本上,您不需要為交叉編譯的目標滾動自己的thread
類(例如,GCC從4.9版開始就支持該類)。
但總的來說,您的方法是正確的。 為了使其適用於各種類,您可以簡單地將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
以避免與c ++標准庫發生沖突。
我想為我正在創建的每個線程使用不同的啟動例程。
回到我使用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()的第二個參數“ this”。
線程將從靜態方法開始:
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);
'int select'和switch / case語句可以運行唯一的threadEntry()。
也許可以安裝“ int select”(在實例中),以便threadEntry()中的后續開關/案例可以運行唯一的方法或threadEntry2_x()。
也許開關/外殼可能安裝在threadEntry2()中。
考慮startApp參數可能是方法指針。
void Foo_t::startApp(<method pointer>);
可以(更直接地)調用方法指針,而不是調用“固定”名稱threadEntry2()。
以上是小問題。
Mutex和在一個實例中運行多個線程是更大的問題。
我確實在單個類實例中有多個線程“運行”。 為此,我在互斥或其他保護機制下使用了關鍵部分。 std :: mutex很方便,並且可以與“ Posix”線程一起使用,但是,在Ubuntu上,我經常使用Posix Process Semaphore,並將其設置為“本地”模式(未命名,未共享)。 PPLSem_t是高效的,適合於封裝在小類中的4個單行方法。
pthread_create tho只允許將靜態函數作為啟動例程,因此無法實例化。
實例化包含靜態方法的類的實例沒有困難。 我不確定您在此聲明/上下文中的含義。
回顧一下我上面詳細介紹的方法,您應該很快就可以在您的類實例中使用Posix線程。
切記檢查堆棧使用情況以及ARM系統上可用的內存量。 Ubuntu的默認堆棧大小為8 MB。 也許您的ARM提供了堆棧大小控制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.