2017-02-04 5 views
0

私はstd::sthreadをバックグラウンドイメージの読み込みに使用しました。私はこのような背景ジョブを作成します。BackgroundPNGLoaderでバックグラウンド読み込みのためのC++スレッド

if (bgThreads.size() > MAX_THREADS_COUNT){ 
    fclose(file); 
    return; 
} 

if (bgThreads.find(id) != bgThreads.end()){ 
    fclose(file); 
    return; 
} 
std::shared_ptr<BackgroundPNGLoader> bg = std::make_shared<BackgroundPNGLoader>(file, id); 
bgThreads[id] = bg; 
bg->thread = std::thread(&BackgroundPNGLoader::Run, bg);  

は、私が持っている:私のメインアプリで

struct BackgroundPNGLoader{ 
    std::atomic<bool> finished; 
    FILE * f; 
    int id; 
    BackgroundPNGLoader() : finished(false) {} 

    void Run(){ 
     ///.... load data 
     finished.store(true); 
    } 
} 

を、私はアップデートを持っている - メインスレッドで実行されているループをレンダリングします。アップデートでは、私が持っている:

std::list<int> finished; 
for (auto & it : bgThreads) 
{ 
    if (it.second->finished) 
    { 
     if (it.second->thread.joinable()) 
     { 
      it.second->thread.join(); 
     } 

     finished.push_back(it.first); 
     //fill image data to texture or whatever need to be done on main thread 
     fclose(it.second->f); 
    } 
} 

for (auto & it : finished) 
{ 
    bgThreads.erase(it); 
} 

が、これは安全であると考えますか?私は、新しいファイルを開く必要があるたびに新しいスレッドを生成することについてちょっと心配しています。最大限の制限はありません。

答えて

1

まず、fopen/fcloseを避け、代わりにC++のファイルI/Oを使用して、例外がスローされたときにリソースがリークする可能性を避けます。さらに、raw std :: threadを使用することはほとんどの場合必要ではありません。非同期タスクの場合、std :: async先物を組み合わせると、となります。 STD内の潜在的な結果を返す のstd ::非同期::将来、後で取り出すことができる。

#include <future> 
#include <thread> 
#include <chrono> 
#include <array> 
#include <iostream> 
#include <random> 

size_t doHeavyWork(size_t arg) 
{ 
    std::mt19937 rng; 
    rng.seed(std::random_device()()); 
    std::uniform_int_distribution<unsigned int> rnd(333, 777); 
    //simulate heavy work... 
    std::this_thread::sleep_for(std::chrono::milliseconds(rnd(rng))); 
    return arg * 33; 
} 

//wrapper function for checking whether a task has finished and 
//the result can be retrieved by a std::future 
template<typename R> 
bool isReady(const std::future<R> &f) 
{ 
    return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; 
} 

int main() 
{ 
    constexpr size_t numTasks = 5; 

    std::array<std::future<size_t>, numTasks> futures; 

    size_t index = 1; 
    for(auto &f : futures) 
    { 
     f = std::async(std::launch::async, doHeavyWork, index); 
     index++; 
    } 

    std::array<bool, numTasks> finishedTasks; 
    for(auto &i : finishedTasks) 
     i = false; 

    size_t numFinishedTasks = 0; 

    do 
    { 
     for(size_t i = 0; i < numTasks; ++i) 
     { 
      if(!finishedTasks[i] && isReady(futures[i])) 
      { 
       finishedTasks[i] = true; 
       numFinishedTasks++; 
       std::cout << "task " << i << " ended with result " << futures[i].get() << '\n'; 
      } 
     } 
    } 
    while(numFinishedTasks < numTasks); 

    std::cin.get(); 
} 

のstd ::非同期スレッドプールを使用して、別のスレッドを起動することができます。

1

まず、コアよりも多くのスレッドを生成しない方がよいでしょう。ここで

そのステータスを知らせる切り離しとさせるスレッドを使った簡単な例です:

#include<thread> 
#include<atomic> 
struct task_data 
{ 

}; 
void doHeavyWork(task_data to_do, std::atomic<bool>& done) 
{ 
    //... do work 
    //--- 
    //-- 
    done = true; 
} 
int main() 
{ 
    unsigned int available_cores = std::thread::hardware_concurrency();//for real parallelism you should not spawn more threads than cores 
    std::vector<std::atomic<bool>> thread_statuses(available_cores); 
    for (auto& b : thread_statuses)//initialize with all cores/threads are free to use 
     b = true; 

    const unsigned int nb_tasks = 100;//how many? 
    std::vector<task_data> tasks_to_realize(nb_tasks); 
    for (auto t : tasks_to_realize)//loop on tasks to spawn a thread for each 
    { 
     bool found = false; 
     unsigned int status_id = 0; 
     while (!found) //loop untill you find a core/thread to use 
     { 
      for (unsigned int i = 0; i < thread_statuses.size(); i++) 
      { 
       if (thread_statuses[i]) 
       { 
        found = true; 
        status_id = i; 
        thread_statuses[i] = false; 
        break; 
       } 
      } 
     } 

     //spawn thread for this task 
     std::thread task_thread(doHeavyWork, std::move(t), std::ref(thread_statuses[status_id])); 
     task_thread.detach();//detach it --> you will get information it is done by it set done to true! 
    } 

    //wait till all are done 
    bool any_thread_running = true; 

    while (any_thread_running)//keep untill all are done 
    { 
     for (unsigned int i = 0; i < thread_statuses.size(); i++) 
     { 

      if (false == thread_statuses[i]) 
      { 
       any_thread_running = true; 
       break; 
      } 
      any_thread_running = false; 
     } 
    } 
    return 0; 
} 
関連する問題