2012-05-15 8 views
8

Ich lerne C++ und habe das in keinem der Bücher, die ich gelesen habe, wirklich gesehen. Ich wollte Code lesen und kommentieren, damit ich besser lernen kann und auf einen seltsamen Codeabschnitt gestoßen bin, der ausgeführt wird, aber keine Bedingung hat. Von dem was ich lese (und von meinen Erfahrungen mit anderen Sprachen, brauchst du ein if, while, for oder sowas für Blöcke).Versteht diesen Code nicht (er läuft ohne Bedingung)

Ich bin auf der tbb Themen Paket suchen, so bin ich nicht sicher, ob es im Zusammenhang mit dem Starten von Threads oder C++ spezifisch (wenn Sie dies nicht als etwas in C++ üblich dann seine wahrscheinlich tdd spezifischen).

Ich denke, ich verstehe, was der Code im Inneren tatsächlich tut, aber ich bin mir nicht sicher, wie es ausgelöst wird oder lief. Irgendwelche Ideen?

Hier ist der Abschnitt:

{ 
     //this is the graph part of the code 
     Graph g; 
     g.create_random_dag(nodes); 
     std::vector<Cell*> root_set; 
     g.get_root_set(root_set); 
     root_set_size = root_set.size(); 
     for(unsigned int trial=0; trial<traversals; ++trial) { 
      ParallelPreorderTraversal(root_set); 
     } 
    } 

P. S. Wenn es hier hilft, ist die gesamte Datei (der obige Code ist in der Mitte der Haupt()).

#include <cstdlib> 
#include "tbb/task_scheduler_init.h" 
#include "tbb/tick_count.h" 
#include "../../common/utility/utility.h" 
#include <iostream> 
#include <vector> 
#include "Graph.h" 

// some forward declarations 
class Cell; 
void ParallelPreorderTraversal(const std::vector<Cell*>& root_set); 

//------------------------------------------------------------------------ 
// Test driver 
//------------------------------------------------------------------------ 
utility::thread_number_range threads(tbb::task_scheduler_init::default_num_threads); 
static unsigned nodes = 1000; 
static unsigned traversals = 500; 
static bool SilentFlag = false; 

//! Parse the command line. 
static void ParseCommandLine(int argc, const char* argv[]) { 
    utility::parse_cli_arguments(
      argc,argv, 
      utility::cli_argument_pack() 
       //"-h" option for for displaying help is present implicitly 
       .positional_arg(threads,"n-of-threads","number of threads to use; a range of the form low[:high], where low and optional high are non-negative integers or 'auto' for the TBB default.") 
       .positional_arg(nodes,"n-of-nodes","number of nodes in the graph.") 
       .positional_arg(traversals,"n-of-traversals","number of times to evaluate the graph. Reduce it (e.g. to 100) to shorten example run time\n") 
       .arg(SilentFlag,"silent","no output except elapsed time ") 
    ); 
} 

int main(int argc, const char* argv[]) { 
    try { 
     tbb::tick_count main_start = tbb::tick_count::now(); //tbb counter start 
     ParseCommandLine(argc,argv); 

     // Start scheduler with given number of threads. 
     std::cout << threads << std::endl; 
     for(int p=threads.first; p<=threads.last; ++p) { 
      tbb::tick_count t0 = tbb::tick_count::now(); //timer 
      tbb::task_scheduler_init init(4); //creates P number of threads 
      srand(2); //generates a random number between 0-2? 
      size_t root_set_size = 0; 
      { 
       //this is the graph part of the code 
       Graph g; 
       g.create_random_dag(nodes); 
       std::vector<Cell*> root_set; 
       g.get_root_set(root_set); 
       root_set_size = root_set.size(); 
       for(unsigned int trial=0; trial<traversals; ++trial) { 
        ParallelPreorderTraversal(root_set); 
       } 
      } 
      tbb::tick_count::interval_t interval = tbb::tick_count::now()-t0; //counter done 
      if (!SilentFlag){ //output the results 
       std::cout 
        <<interval.seconds()<<" seconds using "<<p<<" threads ("<<root_set_size<<" nodes in root_set)\n"; 
      } 
     } 
     utility::report_elapsed_time((tbb::tick_count::now()-main_start).seconds()); 

     return 0; 
    }catch(std::exception& e){ 
     std::cerr 
      << "unexpected error occurred. \n" 
      << "error description: "<<e.what()<<std::endl; 
     return -1; 
    } 
} 
+0

http://en.wikibooks.org/wiki/C%2B%2B_Programming/Scope/Examples - speziell der "// Komplizierte Umfang Programm" Abschnitt – WernerCD

Antwort

18

Nein Sie keine if oder while Anweisung brauchen eine neue Ebene des Umfangs einzuführen. Grundsätzlich öffnet das Symbol { eine neue Gültigkeitsbereichsebene und } beendet es. Es gelten die üblichen Bereichsregeln, zum Beispiel sind Variablen, die in diesem neuen Block definiert sind, außerhalb von undefiniert, am Ende des Blockobjekts werden Destruktoren ausgeführt, und Variablen, die in einer darüber liegenden Bereichsebene die gleichen wie die anderen sind, werden schattiert.

Ein häufiger Anwendungsfall ist in switch Aussagen. Zum Beispiel

switch (a) 
{ 
    case 1: 
    { 
     int i; 
    } 
    case 2: 
    { 
     int i; //note reuse of variable with the same name as in case 1 
    } 
} 

Ohne die {} in den Case-Anweisungen der Compiler über mehrfach definierte Bezeichner beschweren.

+0

interessant..danke Ich frage mich, was ist das wahre Leben verwenden? Ist es sinnvoll, die Aufräumarbeiten (kostenlos, usw.) zu vereinfachen oder was ist der Zweck? – Lostsoul

+3

Ja, es wird für eine feinere Kontrolle über den Geltungsbereich von lokalen Variablen verwendet, und zwar nicht nur dort, wo auf sie zugegriffen werden kann, sondern auch, wenn sie freigegeben werden, wenn sie stackbasierte Objekte sind. –

+2

Sie können auch die gleichen Variablennamen wiederverwenden, wenn Sie dies wünschen, aber dasselbe in einem äußeren und inneren ist nicht so nützlich wie zwei in parallelen Bereichen. – chris

2

Sie können zusätzliche Blöcke wie diese erstellen. Sie werden verwendet, um eine zusätzliche Ebene des Geltungsbereichs aufzuerlegen. In Ihrem Beispiel wird G vor oder nach diesem Block nicht existieren.

7

Das Paar { und } erstellen einen lokalen scope. Am Ende des Gültigkeitsbereichs ruft der Compiler automatisch Destruktoren für alle Stapelvariablen auf (sofern vorhanden), die innerhalb dieses Gültigkeitsbereichs deklariert wurden. In Ihrem Fall werden Destruktoren für g und root_set am Ende des Bereichs aufgerufen.

Eine sehr häufige Anwendung, die ich mir vorstellen kann, ist eine Mutex-Sperre zu erhalten, wenn mit Threads gearbeitet wird. Nehmen wir an, Sie haben eine Klasse mit dem Namen Lock, die ein Mutex-Objekt akzeptiert und eine Sperre für sie annimmt. Dann können Sie einen kritischen Abschnitt von Code umgeben, die von den gleichzeitigen Zugriff geschützt werden muss, wie folgt:

{ 
    Lock lock(mutex); // the Lock constructor will acquire a lock on mutex 

    // do stuff 
} // Here the Lock destructor runs and releases the lock on mutex, allowing 
    // other threads to acquire a lock 

Der Vorteil der oben tun, ist, dass selbst wenn der Code innerhalb des { ... } Block löst eine Ausnahme, den Compiler noch ruft den Destruktor Lock auf, um sicherzustellen, dass die Mutex-Sperre aufgehoben wird.

4

Wenn Sie darauf verweisen, dass der Codeblock über einen zusätzlichen Satz Klammern verfügt, ist dies in der C++ - Programmierung bei kurzlebigen Objekten auf dem Stapel nicht ungewöhnlich, in diesem Fall die Objekte Graph und std::vector<Cell*>. Ein Paar geschweifte Klammern erstellt einen neuen Bereich.Sie müssen nicht an Kontrollanweisungen angehängt werden. In diesem Fall wird ein temporärer Bereich verwendet, um sicherzustellen, dass die Objekte Graph und vector schnell freigegeben werden, wenn sie den Gültigkeitsbereich verlassen. Wenn die zusätzlichen Klammern nicht vorhanden sind, werden die Objekte erst bei der nächsten Iteration der äußeren for-Schleife freigegeben.

Verwandte Themen