2016-07-20 7 views
3
konvertieren

Ich versuche Quicksort mit std::threads zu parallelisieren, und ich bekomme einen Fehler, den ich nicht kenne, seit ich Multithreading gestartet habe . Der Fehler ist wahrscheinlich so einfach, ich hüpfe ständig darüber. Kann jemand bitte etwas Licht auf das Problem werfen. Hier ist der Code und der einzige Fehler, der angezeigt wird:<function-style-cast> Fehler: Konnte nicht von 'initializer list' zu 'std :: thread'

 #define _CRT_SECURE_NO_WARNINGS 

#include <iostream> //cout, endl 
#include <cstdlib> //srand 
#include <algorithm>//copy, random_shuffle 
#include <iterator> //ostream_iterator 
#include "ratio.h" 
#include <vector> 
#include <iostream> 
#include <thread> 
#include "quicksort.h" 
#include "sort_small_arrays.h" 

template< typename T> 
unsigned partition(T* a, unsigned begin, unsigned end) { 
    unsigned i = begin, last = end - 1; 
    T pivot = a[last]; 

    for (unsigned j = begin; j<last; ++j) { 
     if (a[j]<pivot) { 
      std::swap(a[j], a[i]); 
      ++i; 
     } 
    } 
    std::swap(a[i], a[last]); 
    return i; 
} 

/* iterative */ 
#define STACK 
#define xVECTOR 
#define xPRIORITY_QUEUE 

#include <utility> // std::pair 

template <typename T> 
using triple = typename std::pair< T*, std::pair<unsigned, unsigned>>; 

template< typename T> 
struct compare_triples { 
    bool operator() (triple<T> const& op1, triple<T> const& op2) const { 
     return op1.second.first > op2.second.first; 
    } 
}; 

#ifdef STACK 
#include <stack> 
template< typename T> 
using Container = std::stack< triple<T>>; 
#define PUSH push 
#define TOP top 
#define POP pop 
#endif 

#ifdef VECTOR 
#include <vector> 
template< typename T> 
using Container = std::vector< triple<T>>; 
#define PUSH push_back 
#define TOP back 
#define POP pop_back 
#endif 

#ifdef PRIORITY_QUEUE 
#include <queue> 
template< typename T> 
using Container = std::priority_queue< triple<T>, std::vector<triple<T>>, compare_triples<T> >; 
#define PUSH push 
#define TOP top 
#define POP pop 
#endif 

//Thread quicksorts a single range of elements and decrements thread counter at the end 
template< typename T> 
void threadsort_iterative_aux(Container<T> & ranges, int &currentThreads) 
{ 
    triple<T> r = ranges.TOP(); 
    ranges.POP(); 

    T*  a = r.first; 
    unsigned b = r.second.first; 
    unsigned e = r.second.second; 

    //base case 
    if (e - b<6) { 
     switch (e - b) { 
     case 5: quicksort_base_5(a + b); break; 
     case 4: quicksort_base_4(a + b); break; 
     case 3: quicksort_base_3(a + b); break; 
     case 2: quicksort_base_2(a + b); break; 
     } 
     continue; 
    } 

    unsigned q = partition(a, b, e); 

    ranges.PUSH(std::make_pair(a, std::make_pair(b, q))); 
    ranges.PUSH(std::make_pair(a, std::make_pair(q + 1, e))); 
    --currentThreads; 
} 

template< typename T> 
void quicksort(T* a, unsigned begin, unsigned end, int num_threads) 
{ 
    //Number of threads currently running other than the main thread 
    int currentThreads = 0; 

    //Ranges of elements to sort 
    Container<T> ranges; 
    ranges.PUSH(std::make_pair(a, std::make_pair(begin, end))); 

    //Dynamic vector of threads 
    std::vector<std::thread> threads; 

    //Loops till all threads are done AND nothing left to sort 
    while (!ranges.empty() || currentThreads != 0) 
    { 
     //Doesn't bother doing anything if the range is empty but other threads are still running 
     if (!ranges.empty()) 
     { 
      //If we can make more threads, make a thread and give it the top range to sort 
      if (currentThreads < num_threads) 
      { 
       ++currentThreads; 
       threads.push_back(std::thread(threadsort_iterative_aux, std::ref(ranges), std::ref(currentThreads))); 

      } 
      //Starts sorting itself if maximum number of threads are running 
      else 
      { 
       triple<T> r = ranges.TOP(); 
       ranges.POP(); 
       T*  a = r.first; 
       unsigned b = r.second.first; 
       unsigned e = r.second.second; 

       //Optimized sorting of a range between 2 and 5 elements 
       if (e - b < 6) { 
        switch (e - b) { 
        case 5: quicksort_base_5(a + b); break; 
        case 4: quicksort_base_4(a + b); break; 
        case 3: quicksort_base_3(a + b); break; 
        case 2: quicksort_base_2(a + b); break; 
        } 
        continue; 
       } 

       unsigned q = partition(a, b, e); 

       ranges.PUSH(std::make_pair(a, std::make_pair(b, q))); 
       ranges.PUSH(std::make_pair(a, std::make_pair(q + 1, e))); 
      } 
     } 
    } 
} 

template< typename T> 
bool check_is_sorted(T* a, unsigned size) 
{ 
    for (unsigned int i = 1; i<size; ++i) { 
     if (!(a[i - 1] <= a[i])) { 
      return false; 
     } 
    } 
    return true; 
} 

bool test_int(unsigned size, unsigned num_threads) { 
    int* a = new int[size]; 
    for (unsigned i = 0; i<size; ++i) { a[i] = i; } 
    std::srand(static_cast<unsigned int>(std::time(NULL))); 
    std::random_shuffle(a, a + size); 
    quicksort(a, 0, size, num_threads); 
    bool retval = check_is_sorted(a, size); 
    delete[] a; 
    return retval; 
} 

void test0() { 
    if (test_int(200, 1)) { std::cout << "OK\n"; } 
    else { std::cout << "Failed\n"; } 
} 

#include <cstdio> /* sscanf */ 
int main(int argc, char ** argv) 
{ 
    test0(); 
    return 0; 
} 

Severity Code Beschreibung Projektdateizeile Fehler C2440 ‚‘: kann nicht aus konvertieren ‚Initialisiererliste‘ auf ‚std :: thread‘ Linie 145 (enthält:

threads.push_back (std :: Gewinde (threadsort_iterative_aux, std :: ref (Bereiche), std :: ref (currentThreads)));)

Antwort

3

geben Sie einen triple<T> als ersten Parameter zu threadsort_iterative_aux wenn die Schaffung Thread, aber die Funktion erwartet dort eine Container<T> &.

Beachten Sie auch, dass die Parameter in std::ref() auf der Seite des Aufrufers übergeben werden müssen, um Parameter durch non-const-reference mit dieser Signatur zu übergeben.

Dies ist im Grunde das gleiche Verhalten wie bei std::bind: Wenn Sie die std::ref weglassen, wird der Compiler den Wert in die Bindung kopieren und dann diese Kopie als Parameter in den Funktionsaufruf beim Aufruf übergibt. Da die Kopie jedoch unveränderlich ist, wird dies mit nicht-konstanten Referenzen brechen. Das ist eine gute Sache, da es Sie davor schützt, die Nebenwirkungen dieses Parameters versehentlich zu verlieren.

Last but not least bricht der Bind-Mechanismus die Vorlage-Argumentableitung. Da Sie die Funktion nicht tatsächlich an dem Punkt aufrufen, an dem Sie den Thread erstellen, kann der Compiler den Vorlagenparameter für die Funktion nicht automatisch aus den Argumenten ableiten. Sie haben die Parameter explizit geben:

threads.push_back(std::thread(threadsort_iterative_aux<T>, std::ref(ranges), std::ref(currentThreads))); 
//        note the <T> here ---^ 

Da diese ein mächtiges Bündel von bind-Kopfschmerzen sind zu befürchten, mögen Sie vielleicht einfach stattdessen eine Lambda verwenden, die von keinem dieser Fragen leidet:

threads.push_back(std::thread([&]() { threadsort_iterative_aux(ranges, currentThreads); })); 
+0

Hmmm, ich dachte, Ihre Eingabe würde den Fehler beheben. Ich änderte die Zeile in folgende Zeile: threads.push_back (std :: thread (threadsort_iterative_aux, std :: ref (bereiche), std :: ref (currentThreads))); Aber der gleiche Fehler bleibt bestehen. Habe ich es falsch gemacht? Oder haben Sie einen Fehler bemerkt, mit dem ich nach der Behebung des Fehlers umgehen musste? –

+0

@AmrotheStudent Diese Zeile sieht jetzt korrekt aus. Leider ist der von Ihnen gepostete Code unvollständig, was es schwierig macht, den Fehler weiter zu diagnostizieren. Können Sie den Beitrag bearbeiten, um [ein vollständiges, in sich abgeschlossenes Beispiel] (http://stackoverflow.com/help/mcve) anzuzeigen und die vollständige Fehlermeldung, die Sie vom Compiler erhalten, einzubeziehen? – ComicSansMS

+0

Nun, ich bin nicht sicher, wie viel ich dir zeigen soll, also habe ich rausgenommen, was ich für irrelevant hielt. Ich habe die Treiber und Hauptfunktion verlassen, Sie sollten in der Lage sein, kopieren und einfügen und laufen, um den gleichen Fehler jetzt zu sehen. Ich werde den Code wieder bearbeiten, wenn es noch zu viel ist. –