2017-02-04 4 views
0

Ich habe std::sthread für Hintergrundbild geladen. Ich Hintergrund-Job, da dies zu erstellen:C++ - Threads für Hintergrund laden

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);  

In BackgroundPNGLoader, ich habe:

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

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

In meinem Haupt-app, ich habe Update - Render-Schleife in Haupt-Thread ausgeführt wird. In Update habe ich:

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); 
} 

Wird dies als sicher angesehen? Ich bin ein wenig besorgt über das Erstellen neuer Threads jedes Mal, wenn ich neue Datei öffnen muss, gibt es keine maximale Grenze.

Antwort

1

Vermeiden Sie zuerst fopen/fclose und verwenden Sie stattdessen C++ - Datei-I/O, um potenzielle Ressourcenverluste zu vermeiden, wenn Ausnahmen ausgelöst werden. Außerdem ist die Verwendung eines rohen std :: -Threads in den meisten Fällen nicht notwendig. Für asynchrone Tasks ist Std :: Async kombiniert mit Futures ist die Sache zu gehen. std :: async innerhalb eines std ein potenzielles Ergebnis liefert :: Zukunft, die später abgerufen werden können:

#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 :: async separate Threads starten kann einen Thread-Pool verwendet wird.

1

Erstens, spawnen Sie besser nicht mehr Threads als Kerne.

Hier ist ein einfaches Beispiel mit lösen und Themen zu informieren über dessen Status im Stich gelassen:

#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; 
}