èšç®ã°ã©ãã䜿çšããŠãã¿ã¹ã¯éã®äŸåé¢ä¿ã確ç«ããããçšåºŠãŸã§ãããŒã¿ãããŒã¢ãŒããã¯ãã£ããããã°ã©ã ã§å®è£ ã§ããŸãã
ãã®æçš¿ã§ã¯ã ã€ã³ãã«ã¹ã¬ããã£ã³ã°ãã«ãã£ã³ã°ããã㯠ïŒã€ã³ãã«TBBïŒã©ã€ãã©ãªãã€ãŸãtbb :: flow :: graphã¯ã©ã¹ã䜿çšããŠãC ++ã§ãã®ãããªã¢ãã«ãå®è£ ããæ¹æ³ã«ã€ããŠèª¬æããŸãã
ã€ã³ãã«TBBãštbbãšã¯::ãããŒ::ã°ã©ãã¯ã©ã¹
Intel Threading Building Blocks-䞊åããã°ã©ãã³ã°çšã®C ++ãã³ãã¬ãŒãã©ã€ãã©ãªã ãªãŒãã³ãœãŒã¹ã®å®è£ ã§ã¯ç¡æã§é åžãããŸãããåçšçããããŸãã Windows *ãLinux *ãããã³OS X *ã®ãã€ããªåœ¢åŒã§å©çšå¯èœã
TBBã«ã¯ã䞊åã³ã³ãã¥ãŒãã£ã³ã°ã§ã®äœ¿çšã«åãããŠèª¿æŽãããå€ãã®æ¢è£œã®ã¢ã«ãŽãªãºã ãæ§æãããã³ããŒã¿æ§é ããããŸãã å«ããŠãèšç®ã°ã©ãã®å®è£ ãå¯èœã«ããæ§é ããããããã«ã€ããŠèª¬æããŸãã
ãåç¥ã®ããã«ãã°ã©ãã¯é ç¹ïŒããŒãïŒãšãšããžã§æ§æãããŠããŸãã èšç®ã°ã©ãtbb :: flow ::ã°ã©ãããããŒãããšããžãããã³ã°ã©ãå šäœã®ãªããžã§ã¯ãã§æ§æãããŸãã
ã°ã©ãã®ããŒãã«ã¯ãéä¿¡è ãšåä¿¡è ã®ã€ã³ã¿ãŒãã§ãŒã¹ããããã¡ãã»ãŒãžã管çããããããã€ãã®æ©èœãå®è¡ãããããŸãã ãšããžã¯ã°ã©ãã®ããŒããæ¥ç¶ããã¡ãã»ãŒãžããã·ã³ã°ã®ããã£ãã«ãã§ãã
åããŒãã®æ¬äœã¯TBBã¿ã¹ã¯ã§è¡šããããããã®éã«äŸåé¢ä¿ããªãå Žåãä»ã®ããŒããšäžŠè¡ããŠå®è¡ã§ããŸãã TBBã§ã¯ãå€ãã®äžŠåã¢ã«ãŽãªãºã ïŒãŸãã¯ãã¹ãŠïŒãã¿ã¹ã¯ïŒã¯ãŒã¯ãããŒã«ãã£ãŠå®è¡ãããå°ããªäœæ¥é ç®ïŒåœä»€ïŒïŒã«åºã¥ããŠæ§ç¯ãããŸãã ã¿ã¹ã¯éã«äŸåé¢ä¿ãããå¯èœæ§ãããããããã¯ã¹ã¬ããéã§åçã«ååé ã§ããŸãã ã¿ã¹ã¯ã䜿çšããããšã«ãããCPUã§æé©ãªç²åºŠãšããŒããã©ã³ã¹ãå®çŸãããããã«åºã¥ããŠé«ã¬ãã«ã®äžŠåæ§é ïŒtbb :: flow :: graphãªã©ïŒãæ§ç¯ã§ããŸãã
æãåçŽãªäŸåé¢ä¿ã°ã©ã
1ã€ã®ãšããžã§æ¥ç¶ããã2ã€ã®é ç¹ã§æ§æãããã°ã©ãããã®ãã¡ã®1ã€ã¯ãHelloãã2ã€ç®ã®ãWorldãã¯ã次ã®ããã«æŠç¥çã«è¡šç€ºã§ããŸãã
ãããŠãã³ãŒãã§ã¯æ¬¡ã®ããã«ãªããŸãã
#include <iostream> #include <tbb/flow_graph.h> int main(int argc, char *argv[]) { tbb::flow::graph g; tbb::flow::continue_node< tbb::flow::continue_msg > h( g, []( const tbb::flow::continue_msg & ) { std::cout << "Hello "; } ); tbb::flow::continue_node< tbb::flow::continue_msg > w( g, []( const tbb::flow::continue_msg & ) { std::cout << "World\n"; } ); tbb::flow::make_edge( h, w ); h.try_put(tbb::flow::continue_msg()); g.wait_for_all(); return 0; }
ããã«ãããã°ã©ãgã®ãªããžã§ã¯ããšã¿ã€ãcontinue_nodeã®2ã€ã®ããŒã-hããã³wãäœæãããŸãã ãããã®ããŒãã¯ãcontinue_msgã¿ã€ãã®ã¡ãã»ãŒãžïŒå éšå¶åŸ¡ã¡ãã»ãŒãžïŒãéåä¿¡ããŸãã ãããã¯ãå è¡ããã¡ãã»ãŒãžãåä¿¡ããåŸã«ã®ã¿ããŒãæ¬äœãå®è¡ãããå Žåã«ãäŸåé¢ä¿ã°ã©ããæ§ç¯ããããã«äœ¿çšãããŸãã
continue_nodeã®ããããã¯ãæ¡ä»¶ä»ãã§æçšãªã³ãŒããå®è¡ããŸã-ãHelloããšãWorldããåºåããŸãã ããŒãã¯ãmake_edgeã¡ãœããã䜿çšããŠãšããžã§çµåãããŸãã ãã¹ãŠãèšç®ã°ã©ãã®æ§é ã®æºåãã§ããŠããŸã-try_putã¡ãœããã§ã¡ãã»ãŒãžãéä¿¡ããããšã§ãå®è¡ã®ããã«å®è¡ã§ããŸãã 次ã«ãã°ã©ããæ©èœãããã¹ãŠã®ã¿ã¹ã¯ãå®äºããããšã確èªããããã«ãwait_for_allã¡ãœããã䜿çšããŠåŸ æ©ããŸãã
ã·ã³ãã«ãªã¡ãã»ãŒãžã³ã°ã°ã©ã
ããã°ã©ã ãxã«å¯ŸããŠ1ãã10ãŸã§ã®åŒx 2 + x 3ãèšç®ããããšãæ³åããŠãã ãããã¯ããããã¯æãé£ããèšç®ã¿ã¹ã¯ã§ã¯ãããŸãããããã¢ã³ã¹ãã¬ãŒã·ã§ã³ã«ã¯éåžžã«é©ããŠããŸãã
åŒã®ã«ãŠã³ããã°ã©ã圢åŒã§è¡šç€ºããŠã¿ãŸãããã æåã®ããŒãã¯ãçä¿¡ããŒã¿ã¹ããªãŒã ããxå€ãååŸããç«æ¹äœããã³äºä¹ãããããŒãã«éä¿¡ããŸãã ã¹ãä¹æŒç®ã¯äºãã«ç¬ç«ããŠããã䞊è¡ããŠå®è¡ã§ããŸãã èµ·ããããäžåè¡¡ã解æ¶ããããã«ãçµæããããã¡ããŒãã«è»¢éããŸãã 次ã«ãçµ±åããŒãããããŸããããã¯ãéèšããŒãã®çŽ¯ä¹ã®çµæãæäŸããèšç®ãçµäºããŸãã
ãã®ãããªã°ã©ãã®ã³ãŒãïŒ
#include <tbb/flow_graph.h> #include <windows.h> using namespace tbb::flow; struct square { int operator()(int v) { printf("squaring %d\n", v); Sleep(1000); return v*v; } }; struct cube { int operator()(int v) { printf("cubing %d\n", v); Sleep(1000); return v*v*v; } }; class sum { int &my_sum; public: sum( int &s ) : my_sum(s) {} int operator()( std::tuple<int,int> v ) { printf("adding %d and %d to %d\n", std::get<0>(v), std::get<1>(v), my_sum); my_sum += std::get<0>(v) + std::get<1>(v); return my_sum; } }; int main(int argc, char *argv[]) { int result = 0; graph g; broadcast_node<int> input (g); function_node<int,int> squarer( g, unlimited, square() ); function_node<int,int> cuber( g, unlimited, cube() ); buffer_node<int> square_buffer(g); buffer_node<int> cube_buffer(g); join_node< std::tuple<int,int>, queueing > join(g); function_node<std::tuple<int,int>,int> summer( g, serial, sum(result) ); make_edge( input, squarer ); make_edge( input, cuber ); make_edge( squarer, square_buffer ); make_edge( squarer, input_port<0>(join) ); make_edge( cuber, cube_buffer ); make_edge( cuber, input_port<1>(join) ); make_edge( join, summer ); for (int i = 1; i <= 10; ++i) input.try_put(i); g.wait_for_all(); printf("Final result is %d\n", result); return 0; }
ããã»ã¹ãèŠèŠåããããã«SleepïŒ1000ïŒé¢æ°ãè¿œå ãããŸããïŒäŸã¯Windowsã§ã³ã³ãã€ã«ãããä»ã®ãã©ãããã©ãŒã ã§åçã®åŒã³åºãã䜿çšããŸãïŒã ãã®åŸããã¹ãŠãæåã®äŸã®ããã«ãªããŸã-ããŒããäœæãããšããžãšçµã¿åãããŠå®è¡ããããã«å®è¡ããŸãã function_nodeã®2çªç®ã®ãã©ã¡ãŒã¿ãŒïŒç¡å¶éãŸãã¯ã·ãªã¢ã«ïŒã¯ã䞊åå®è¡ã§ããããŒãæ¬äœã®ã€ã³ã¹ã¿ã³ã¹ã®æ°ã決å®ããŸãã ã¿ã€ãjoin_nodeã®ããŒãã¯ãåå ¥åã§ã®å ¥åããŒã¿/ã¡ãã»ãŒãžã®æºåã決å®ããäž¡æ¹ã®æºåãã§ããããããããstd :: tupleã®åœ¢åŒã§æ¬¡ã®ããŒãã«æž¡ããŸãã
TBB ::ãããŒ::ã°ã©ãã䜿çšãããã£ããŒå²åŠè ã®åé¡ã®è§£æ±º
ãŠã£ãããã£ã¢ãã ïŒ
ãé£äºããå²åŠè ã®åé¡ãã¯ãã³ã³ãã¥ãŒã¿ãŒãµã€ãšã³ã¹ã§äœ¿çšãããå€å žçãªäŸã§ããã䞊åã¢ã«ãŽãªãºã ã®èšèšã«ãããåæã®åé¡ãšããããã®åé¡ã解決ããææ³ã瀺ããŠããŸãã
ã¿ã¹ã¯ã§ã¯ãæ°äººã®å²åŠè ãããŒãã«ã«åº§ã£ãŠãããé£ã¹ãããšãèããããšãã§ããŸãããåæã«ã¯ã§ããŸããã ç§ãã¡ã®ããŒãžã§ã³ã§ã¯ãå²åŠè ã¯ç®žã§éººãé£ã¹ãŸã-é£ã¹ãã«ã¯2æ¬ã®æ£ãå¿ èŠã§ããããããããå©çšå¯èœã§ãïŒ
ãã®ãããªç¶æ³ã§ã¯ãããšãã°ãåå²åŠè ãæãå·Šã«ã€ãããšãããããã¯ïŒãããããã¯ïŒãçºçããå¯èœæ§ãããããããã€ããŒéã®ã¢ã¯ã·ã§ã³ã®åæãå¿ èŠã§ãã
tbb :: flow :: graphã®åœ¢åŒã§å²åŠè ã®ããŒãã«ãæ瀺ããŠã¿ãŸãããã åå²åŠè ã¯ãã¹ãã£ãã¯ããã£ããã£ããããã®join_nodeãšããé£ã¹ããããã³ãèãããã¿ã¹ã¯ãéæããããã®function_nodeã®2ã€ã®ããŒãã§è¡šãããŸãã ããŒãã«äžã®ã¹ãã£ãã¯ã®é 眮ã¯ãqueue_nodeãä»ããŠå®è£ ãããŸãã queue_nodeãã¥ãŒã«ã¯è€æ°ã®ã¯ã³ããå«ããããšã¯ã§ããŸãããã¯ã³ããããå Žåã¯ããã£ããã£ã«äœ¿çšã§ããŸãã ã°ã©ãã¯æ¬¡ã®ããã«ãªããŸãã
ããã€ãã®å®æ°ãšããããŒãã¡ã€ã«ãæã€ã¡ã€ã³é¢æ°ïŒ
#include <windows.h> #include <tbb/flow_graph.h> #include <tbb/task_scheduler_init.h> using namespace tbb::flow; const char *names[] = { "Archimedes", "Aristotle", "Democritus", "Epicurus", "Euclid", "Heraclitus", "Plato", "Pythagoras", "Socrates", "Thales" }; âŠ. int main(int argc, char *argv[]) { int num_threads = 0; int num_philosophers = 10; if ( argc > 1 ) num_threads = atoi(argv[1]); if ( argc > 2 ) num_philosophers = atoi(argv[2]); if ( num_threads < 1 || num_philosophers < 1 || num_philosophers > 10 ) exit(1); tbb::task_scheduler_init init(num_threads); graph g; printf("\n%d philosophers with %d threads\n\n", num_philosophers, num_threads); std::vector< queue_node<chopstick> * > places; for ( int i = 0; i < num_philosophers; ++i ) { queue_node<chopstick> *qn_ptr = new queue_node<chopstick>(g); qn_ptr->try_put(chopstick()); places.push_back( qn_ptr ); } std::vector< philosopher > philosophers; for ( int i = 0; i < num_philosophers; ++i ) { philosophers.push_back( philosopher( names[i], g, places[i], places[(i+1)%num_philosophers] ) ); g.run( philosophers[i] ); } g.wait_for_all(); for ( int i = 0; i < num_philosophers; ++i ) philosophers[i].check(); return 0; }
ã³ãã³ãã©ã€ã³ãã©ã¡ãŒã¿ãåŠçããåŸãã¿ã€ãtbb :: task_scheduler_initã®ãªããžã§ã¯ããäœæããããšã«ãããã©ã€ãã©ãªãåæåãããŸãã ããã«ãããåæåã®æéãå¶åŸ¡ããã¹ã¬ãããã³ãã©ãŒã®æ°ãæåã§èšå®ã§ããŸãã ããããªããšãåæåã¯èªåçã«è¡ãããŸãã 次ã«ãã°ã©ãgã®ãªããžã§ã¯ããäœæãããŸãã ãæã®å Žæãqueue_nodeã¯std :: vectorã«é 眮ãããåæã¯æã«é 眮ãããŸãã
ä»ã®å²åŠè ãåæ§ã®æ¹æ³ã§äœæãããŸã-std :: vectorã«é 眮ãããŸãã åå²åŠè ã®ãªããžã§ã¯ãã¯ãã°ã©ããªããžã§ã¯ãã®runé¢æ°ã«æž¡ãããŸãã å²åŠè ã¯ã©ã¹ã«ã¯æŒç®åïŒïŒãå«ãŸããruné¢æ°ã䜿çšãããšãã°ã©ãgãªããžã§ã¯ãã®ã«ãŒãã¿ã¹ã¯ã®åã§ããã¿ã¹ã¯ã§ãã®ãã¡ã³ã¯ã¿ãŒãå®è¡ã§ããŸãã ãããã£ãŠãg.wait_for_allïŒïŒã®åŒã³åºãäžã«ãããã®ã¿ã¹ã¯ãå®äºãããŸã§åŸ ã€ããšãã§ããŸãã
å²åŠè ã¯ã©ã¹ïŒ
const int think_time = 1000; const int eat_time = 1000; const int num_times = 10; class chopstick {}; class philosopher { public: typedef queue_node< chopstick > chopstick_buffer; typedef join_node< std::tuple<chopstick,chopstick> > join_type; philosopher( const char *name, graph &the_graph, chopstick_buffer *left, chopstick_buffer *right ) : my_name(name), my_graph(&the_graph), my_left_chopstick(left), my_right_chopstick(right), my_join(new join_type(the_graph)), my_function_node(NULL), my_count(new int(num_times)) {} void operator()(); void check(); private: const char *my_name; graph *my_graph; chopstick_buffer *my_left_chopstick; chopstick_buffer *my_right_chopstick; join_type *my_join; function_node< join_type::output_type, continue_msg > *my_function_node; int *my_count; friend class node_body; void eat_and_think( ); void eat( ); void think( ); void make_my_node(); };
åå²åŠè ã«ã¯ãååãã°ã©ããªããžã§ã¯ããžã®ãã€ã³ã¿ãå·Šå³ã¹ãã£ãã¯ãžã®ãã€ã³ã¿ãjoin_nodeããŒããfunction_nodeé¢æ°ããŒããããã³å²åŠè ãèããŠé£ã¹ãåæ°ãã«ãŠã³ãããmy_countã«ãŠã³ã¿ãŒããããŸãã
ã°ã©ãå®è¡é¢æ°ã«ãã£ãŠåŒã³åºãããoperatorïŒïŒïŒïŒã¯ãå²åŠè ãæåã«èããŠããã°ã©ãã«ã¢ã¿ããããããã«å®è£ ãããŸãã
void philosopher::operator()() { think(); make_my_node(); } think eat : void philosopher::think() { printf("%s thinking\n", my_name ); Sleep(think_time); printf("%s done thinking\n", my_name ); } void philosopher::eat() { printf("%s eating\n", my_name ); Sleep(eat_time); printf("%s done eating\n", my_name ); }
make_my_nodeã¡ãœããã¯é¢æ°ããŒããäœæãããããšjoin_nodeã®äž¡æ¹ãã°ã©ãã®æ®ãã®éšåã«é¢é£ä»ããŸãã
void philosopher::make_my_node() { my_left_chopstick->register_successor( input_port<0>(*my_join) ); my_right_chopstick->register_successor( input_port<1>(*my_join) ); my_function_node = new function_node< join_type::output_type, continue_msg >( *my_graph, serial, node_body( *this ) ); make_edge( *my_join, *my_function_node ); }
ã°ã©ãã¯åçã«äœæãããããšã«æ³šæããŠãã ãã-ãšããžã¯register_successorã¡ãœããã«ãã£ãŠåœ¢æãããŸãã æåã«ã°ã©ãæ§é ãå®å šã«äœæããŠããå®è¡ããå¿ èŠã¯ãããŸããã TBBã«ã¯ãã°ã©ããæ¢ã«å®è¡ãããŠããå Žåã§ããæ°ããããŒããåé€ããã³è¿œå ããå Žåã§ãããã®æ§é ããã®å Žã§å€æŽããæ©èœããããŸãã ããã«ãããèšç®ã°ã©ãã®æŠå¿µãããã«æè»ã«ãªããŸãã
node_bodyã¯ã©ã¹ã¯ãå²åŠè :: eat_and_thinkïŒïŒã¡ãœãããåŒã³åºãåçŽãªãã¡ã³ã¯ã¿ãŒã§ãã
class node_body { philosopher &my_philosopher; public: node_body( philosopher &p ) : my_philosopher(p) { } void operator()( philosopher::join_type::output_type ) { my_philosopher.eat_and_think(); } };
eat_and_thinkã¡ãœããã¯eatïŒïŒé¢æ°ãåŒã³åºããã«ãŠã³ã¿ãŒããã¯ãªã¡ã³ãããŸãã ãã®åŸãå²åŠè ã¯æãããŒãã«ã«çœ®ããŠèããŸãã ãããŠã圌ãé£ã¹ãŠæ£ããåæ°ãèããå Žåã圌ã¯ããŒãã«ããç«ã¡äžãã-remove_successorã¡ãœããã䜿çšããŠãjoin_nodeãšã°ã©ããšã®æ¥ç¶ãåæããŸãã ããã§ããã°ã©ãã®åçæ§é ã衚瀺ãããŸããããŒãã®äžéšã¯åé€ãããæ®ãã¯æ©èœãç¶ããŸãã
void philosopher::eat_and_think( ) { eat(); --(*my_count); if (*my_count > 0) { my_left_chopstick->try_put( chopstick() ); my_right_chopstick->try_put( chopstick() ); think(); } else { my_left_chopstick->remove_successor( input_port<0>(*my_join) ); my_right_chopstick->remove_successor( input_port<1>(*my_join) ); my_left_chopstick->try_put( chopstick() ); my_right_chopstick->try_put( chopstick() ); } }
ãã®ã°ã©ãã§ã¯ãqueue_nodeïŒã¹ãã£ãã¯ã®å ŽæïŒããå²åŠè ãããæ£ç¢ºã«ã¯join_nodeãžã®ãšããžããããŸãã ããããå察ã®æ¹åã§ã¯ããããŸããã ãã ããeat_and_thinkã¡ãœããã¯ãæããã¥ãŒã«æ»ãããã«try_putãåŒã³åºãããšãã§ããŸãã
mainïŒïŒé¢æ°ã®æåŸã«ããã¹ãŠã®å²åŠè ã«å¯ŸããŠcheckã¡ãœãããåŒã³åºãããå²åŠè ãæ£ããåæ°ãé£ã¹ãŠèããå¿ èŠãªãã¯ãªãŒãã³ã°ããè¡ãããšã確èªããŸãã
void philosopher::check() { if ( *my_count != 0 ) { printf("ERROR: philosopher %s still had to run %d more times\n", my_name, *my_count); exit(1); } else { printf("%s done.\n", my_name); } delete my_function_node; delete my_join; delete my_count; }
ãã®äŸã®ãããããã¯ã¯ãjoin_nodeã®äœ¿çšã«ããçºçããŸããã ãã®ã¿ã€ãã®ããŒãã¯ãäž¡æ¹ã®å ¥åããåãåã£ããªããžã§ã¯ãããstd :: tupleãäœæããŸãã ãã®å Žåãå ¥åããŒã¿ã¯åä¿¡çŽåŸã«æ¶è²»ãããŸããã join_nodeã¯ãæåã«äž¡æ¹ã®å ¥åã«ããŒã¿ã衚瀺ããããŸã§åŸ æ©ããŠãããé çªã«äºçŽãè©Šã¿ãŸãã ãã®æäœãæåããå Žåã®ã¿-ãããã¯ãæ¶è²»ããããstd :: tupleããããããäœæãããŸãã å°ãªããšã1ã€ã®å ¥åããã£ãã«ãã®äºçŽãããŸããããªãå Žåããã§ã«äºçŽãããŠãããã®ã¯è§£æŸãããŸãã ã€ãŸã å²åŠè ã1æ¬ã®æãæãŸããããšãã§ãããã2æ¬ç®ãå¿ããå Žåã圌ã¯æåã®æãæŸããŠåŸ æ©ããé£äººãç¡é§ã«ãããã¯ããŸããã
ãã®é£äºå²åŠè ã®äŸã¯ãTBBã°ã©ãã®ããã€ãã®æ©èœã瀺ããŠããŸãã
- join_nodeã䜿çšããŠãªãœãŒã¹ã¢ã¯ã»ã¹ã®åæã確ä¿ãã
- åçãªã°ã©ãæ§ç¯-æäœäžã«ããŒããè¿œå ããã³åé€ã§ããŸã
- åäžã®å ¥å£ããã³åºå£ç¹ããªããããã°ã©ãã«ã«ãŒããããå ŽåããããŸã
- ã°ã©ãå®è¡æ©èœã䜿çšãã
ããŒãã®çš®é¡
tbb ::ãããŒ::ã°ã©ãã¯ãããªãå¹ åºãããŒããªãã·ã§ã³ãæäŸããŸãã ãããã¯ãæ©èœããããã¡ãªã³ã°ãçµåãšåé¢ããã®ä»ã®4ã€ã®ã°ã«ãŒãã«åããããšãã§ããŸãã å¡äŸä»ãã®ããŒãã¿ã€ãã®ãªã¹ãïŒ
ãããã«
ã€ã³ãã«TBBã§å®è£ ãããã°ã©ãã䜿çšããŠããéæ§é å䞊ååŠçããšãåŒã°ãã䞊åããã°ã©ã ã®è€éã§èå³æ·±ãããžãã¯ãäœæã§ããŸãã èšç®ã°ã©ãã䜿çšãããšãã¿ã¹ã¯éã®äŸåé¢ä¿ãæŽçããã¡ãã»ãŒãžãšã€ãã³ãã®éä¿¡ã«åºã¥ããŠã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸãã
ã°ã©ãæ§é ã¯éçãŸãã¯åçã®ããããã§ããããŒããšãšããžã¯ãã®å Žã§è¿œå ããã³åé€ã§ããŸãã åã ã®ãµãã°ã©ãã倧ããªã°ã©ãã«æ¥ç¶ã§ããŸãã
ã»ãšãã©ã®è³æã¯ãæµ·å€ã®ååã®è±èªã®åºçç©ã«åºã¥ããŠããŸãã
èå³ããã人ã®ããã«ãè©ŠããŠã¿ãŠãã ããïŒ
ã€ã³ãã«ã¹ã¬ããã£ã³ã°ãã«ãã£ã³ã°ãããã¯ã©ã€ãã©ãªïŒãªãŒãã³ãœãŒã¹ããŒãžã§ã³ïŒãããŠã³ããŒãããŸãã
http://threadingbuildingblocks.org
Intel TBBã®åçšããŒãžã§ã³ïŒæ©èœçã«éãã¯ãããŸããïŒïŒ
http://software.intel.com/en-us/intel-tbb
TBBã«é¢ããè±èªã®ããã°::ãããŒ::ã°ã©ãïŒ
http://software.intel.com/en-us/tags/17218
http://software.intel.com/en-us/tags/17455