2012-02-13 113 views
2

我想爲每個Page對象的實例都有一個線程。在一個時間只有一個可以執行(只檢查指針指向當前正在運行的線程是可連接或不..)std :: thread:如何在類體中聲明一個線程作爲普通成員?

class Page : public std::vector<Step> 
{ 
    // .... 
    void play(); 
    void start(); // check if no other thread is running. if there is a running thread, return. else join starter 
    std::thread starter; // std::thread running this->play() 
    static std::thread* current; // pointer to current running thread 
    // ... 
}; 

我希望能夠火起來Page對象starter線程。例如這樣的:

Page x , y , z; 
// do some stuff for initialize pages.. 
x.start(); 
// do some other work 
y.start(); // if x is finished, start y otherwise do nothing 
// do some other lengthy work 
z.start(); // if x and y are not running, start z 

我不能管理申報started作爲Page成員。我發現這是因爲std::thread只能在聲明時初始化。 (或類似的東西,導致它不可能複製一個線程)

void x() 
{ 
} 
//... 
std::thread t(x);   // this is ok 
std::thread r;    // this is wrong, but I need this ! 
r = std::thread(this->y); // no hope 
r = std::thread(y);  // this is wrong too 
+5

Arrg我的眼睛初始化順序的問題!一個共享的靜態容器繼承。 – 2012-02-13 19:35:08

+0

@deft_code:我知道容器繼承的問題。考慮到我的'頁面'對象的生命週期與整個程序的生命週期有關,頁面的析構函數將永遠不會被調用,直到所有事情完成,甚至分段錯誤並不重要。 (我試圖避免重寫幾個3周齡的2500行代碼,而YES,我是有史以來最慢的cs的學生......) – 2012-02-13 20:03:37

+0

你想要什麼時候做'y'什麼時候做'x'仍然很忙?這聽起來像你希望它默默無聞,但這看起來不對。如果'start'被調用兩次,'Page'會做什麼? – 2012-02-13 20:59:05

回答

3

可以初始化線程的功能,通過使用一個成員初始化列表運行。例如,考慮此構造爲Page

class Page { 
public: 
    Page(); // For example 

private: 
    std::thread toRun; 
}; 

Page::Page() : toRun(/* function to run */) { 
    /* ... */ 
} 

注意我們如何使用Page構造函數中的初始化列表來初始化toRun的功能應該被運行。因爲如果你已經宣佈它作爲一個局部變量

std::string toRun(/* function to run */); 

不過這樣一來,toRun被初始化,還有我認爲你必須在你的代碼解決兩個主要問題。首先,你應該而不是繼承自std::vector或任何標準集合類。這些類沒有標記爲virtual的析構函數,這意味着如果您試圖將Page視爲std::vector,則可以輕鬆調用未定義的行爲。相反,考慮將Page作爲直接子對象保留std::vector。此外,你不應該暴露該班級的std::thread成員。一般來說,數據成員應該是private來增加封裝,使得將來更容易修改類,並防止人們破壞類的所有不變量。

希望這會有所幫助!

+0

問題是我想'toRun'運行'Page'的成員函數換句話說:'Page :: Page():toRun(this-> play)'。 – 2012-02-13 19:38:28

+0

@Sorush Rabiee-當然,你可以做到這一點!只需將'toRun'初始化爲'[this](){this-> play();}'使用新的C++ 11 lambda表達式。 – templatetypedef 2012-02-13 19:39:35

+0

不起作用... – 2012-02-13 19:57:40

2

從不公開繼承std容器,除非該代碼旨在丟棄代碼。誠實地說,當推動推動時,經常丟棄代碼變成產品代碼是很可怕的。

我明白你不想重現整個std::vector界面。這是單調乏味的寫作,很難維持,並且誠實地可能會產生錯誤。

試試這個

class Page: private std::vector 
{ 
public: 
    using std::vector::push_back; 
    using std::vector::size; 
    // ... 
}; 

忽略std::vector問題本應該對這個問題的併發部分的工作。

class Page 
{ 
    ~Page(void) 
    { 
    m_thread.join(); 
    } 

    void start(void); 

private: 

    // note this is private, it must be to maintain the s_running invariant 
    void play(void) 
    { 
    assert(s_current == this); 

    // Only one Page at a time will execute this code. 

    std::lock_guard<std::mutex> _{ s_mutex }; 
    s_running = nullptr; 
    } 

    std::thread m_thread; 

    static Page* s_running; 
    static std::mutex s_mutex; 
}; 

Page* Page::s_running = nullptr; 
std::mutex Page::s_mutex; 
std::condition Page::s_condition; 

void Page::start(void) 
{ 
    std::lock_guard<std::mutex> _{ s_mutex }; 

    if(s_running == nullptr) 
    { 
    s_running = this; 
    m_thread = std::thread{ [this](){ this->play(); } }; 
    } 
} 

這種解決方案可能需要如果Page被實例化之前main()

相關問題