2013-05-27 68 views
0

我正在學校項目上工作,並且在使用我的課程時遇到線程問題。我有一個類(下載)有一個線程,當線程完成工作時,將一個指向atomic<bool>的指針設置爲true,另一個類在其自己的線程上運行,並且當該線程看到「下載」完成時的狀態從列表中刪除它。隨着現在設置的類,任何指向atomic<bool>的指針上的商店都將只更新最近創建的對象,以便只有列表的末尾才能完成設置。下面的代碼...C++ 11原子,存儲隻影響最近創建的對象

class Download 
{ 
private: 
    Show *showPtr; 
    int season; 
    int episode; 
    int downloadTime; 
    atomic<bool> complete; 
    thread downloadThread; 
    // Edit: Hans Passant's solution to compiler error problems - 
    Download(const Download&); 
    Download& operator=(const Download&); 
public: 
    Download(Show * showPtr); 
    string status(bool &complete); 
    bool operator==(const Download &other) const; 
    friend void blockThenSetComplete(Download *dl); 
}; 


Download::Download(Show * showPtr) 
    : showPtr(showPtr) 
{ 
    complete.store(false); 
    // Randomly pick a download time from 20 - 30 seconds. 
    downloadTime = rand() % 11 + 20; 
    // Track which episode this thread is downloading. 
    season = showPtr->getNumberDownloaded()/showPtr->getNumberOfEpisodesPerSeason() + 1; 
    episode = showPtr->getNumberDownloaded() - showPtr->getNumberOfEpisodesPerSeason() * (season - 1) + 1; 
    showPtr->incrementDownloaded(); 
    // Download the episode and return control. 
    downloadThread = thread(blockThenSetComplete, this); 
} 

string Download::status(bool & complete) 
{ 
    complete = this->complete.load(); 
    stringstream ss; 
    ss << showPtr->getTitle() << " S" << season << "E" << episode; 
    return ss.str(); 
} 

void blockThenSetComplete(Download *dl) 
{ 
    this_thread::sleep_for(chrono::seconds(dl->downloadTime)); 
    dl->complete.store(true); 
} 

bool Download::operator==(const Download &other) const 
{ 
    if (other.showPtr == showPtr && 
     other.season == season && 
     other.episode == episode) 
     return true; 
    else 
     return false; 
} 

和下載管理器...

// Ran as a thread, will fire up or tear down downloads as appropriate. 
void downloadManager(Model *model) 
{ 
    while(true) 
    { 
     bool callNotify = false; 
     // monitoring shows 
     if (model->shows.size() != 0) 
     { 
      // connections available 
      if (model->account.getTotalConnectionCount() > model->account.getTotalActiveCount()) 
      { 
       // check each show 
       for (list<Show>::iterator showIt = model->shows.begin(); showIt != model->shows.end(); showIt++) 
       { 
        // find a show that needs a download 
        if (~((*showIt).allDownloading())) 
        { 
         // must check connections again 
         if (model->account.getTotalConnectionCount() > model->account.getTotalActiveCount()) 
         { 
          // Reserve connection and add to list. 
          model->account.reserveConnection(); 
          model->downloads.push_back(Download(&(*showIt))); 
          callNotify = true; 
         } 
        } 
       } 
      } 
     } 
     // monitoring downloads 
     if (model->downloads.size() != 0) 
     { 
      // check each download 
      for (list<Download>::iterator downIt = model->downloads.begin(); downIt != model->downloads.end(); downIt++) 
      { 
       // find a finished download 
       bool finished = false; 
       (*downIt).status(finished); 
       if (finished) 
       { 
        // Remove from list, release connection, break as iterators are now invalid 
        model->downloads.remove(*downIt); 
        model->account.releaseConnection(); 
        callNotify = true; 
        break; 
       } 
      } 
     } 

     if (callNotify) 
      model->notify(); 
     // Check periodically. 
     this_thread::sleep_for(chrono::seconds(10)); 
    } 
} 

我知道有沒有析構函數指針,那就是要使立即線程設置後關閉出於某種原因被稱爲並讓程序保釋。我使用指針的原因是我似乎無法將線程或原子作爲數據成員。現在這可能是我的問題的真正來源。如果我去通過並更改指向這些類的實例,我得到這些錯誤:

Error 3 error C2248: 'std::atomic<bool>::atomic' : cannot access private member declared in class 'std::atomic<bool>' e:\users\robert\documents\visual studio 2012\projects\pvrsim\pvrsim\download.h 36 1 PVRsim 
Error 4 error C2248: 'std::thread::thread' : cannot access private member declared in class 'std::thread' e:\users\robert\documents\visual studio 2012\projects\pvrsim\pvrsim\download.h 36 1 PVRsim 

任何有更多的經驗能夠挑選出我在做什麼錯?

+0

你可以發佈代碼插入並從列表中刪除'下載'對象? – hmjd

回答

1

值得看看std :: thread和std :: atomic類的定義,以確切地查看它所抱怨的私有成員。當你偷看的VC /包括例如/蘇氨酸/線程頭文件,你會看到這一點:

private: 
    thrd_t _Thr; 
    bool _Joinable; 
    friend class thread_group; 

    thread(const thread&); // not defined 
    thread& operator=(const thread&);  // not defined 

注後兩個成員,分別拷貝構造函數和賦值操作符。請注意0​​評論。

這是C++中的一個非常標準的技巧,用於防止客戶端代碼複製類的對象。這對於s​​td :: thread來說非常重要,不存在複製線程的情況。有一個的方式太多的運行時狀態與一個線程關聯,它有自己的棧和它自己的執行狀態。沒辦法,你可以複製它。或者做一個有用的,模Unix的fork()。

這個難以猜測的問題部分是爲什麼編譯器試圖使用複製構造函數。這是在你看不到的代碼中完成的。當你沒有聲明自己的拷貝構造函數和賦值運算符時,C++編譯器會爲你創建一個。這將調用你的成員類的相應成員。這是私人,因此編譯錯誤。

所以你需要做的是防止你的自己的類也被複制。哪一個是正確的,創建一個Download類對象的副本是沒有意義的。你用確切的這樣做,std ::線程使用相同的技術,使您的副本構造函數和賦值運算符私人,而不是定義它們。修復:

private: 
    Download(const Downoad&);    // not defined 
    Download& operator=(const Download&); // not defined 

編譯器現在不再嘗試生成它們自己版本的這些成員,問題解決了。

+0

這解決了無法將線程或原子作爲數據成員的問題,但現在編譯器正在說它需要訪問這些運算符,可以使用Download :: operator = xutility中的矢量(第2466行,移動模板函數)或Download :: Download in list(1587行,列表刪除功能)。如果我使用線程,是否需要使用自己的算法在自己的容器中管理這些數據?我添加了下載管理器代碼。 – CANTPRO

+0

同樣的問題,該對象的副本將被放入一個向量中。相反,將指針存儲在向量中。用std :: shared_ptr <>包裝它通常是合適的。 –

+0

輝煌的男人謝謝。 – CANTPRO