簡體   English   中英

Posix線程類和啟動例程(pthread)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM