<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 第?6?章?多線程 ### 目錄 * [6.1 概述](multithreading.html#multithreading_general) * [6.2 線程管理](multithreading.html#multithreading_thread_management) * [6.3 同步](multithreading.html#multithreading_synchronization) * [6.4 線程本地存儲](multithreading.html#multithreading_thread_local_storage) * [6.5 練習](multithreading.html#multithreading_exercises) [![](https://box.kancloud.cn/2016-02-29_56d41c2d6e214.gif)](http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh) 該書采用 [Creative Commons License](http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh) 授權 ## 6.1.?概述 線程就是,在同一程序同一時間內允許執行不同函數的離散處理隊列。 這使得一個長時間去進行某種特殊運算的函數在執行時不阻礙其他的函數變得十分重要。 線程實際上允許同時執行兩種函數,而這兩個函數不必相互等待。 一旦一個應用程序啟動,它僅包含一個默認線程。 此線程執行 `main()` 函數。 在 `main()`中被調用的函數則按這個線程的上下文順序地執行。 這樣的程序稱為單線程程序。 反之,那些創建新的線程的程序就是多線程程序。 他們不僅可以在同一時間執行多個函數,而且這在如今多核盛行的時代顯得尤為重要。 既然多核允許同時執行多個函數,這就使得對開發人員相應地使用這種處理能力提出了要求。 然而線程一直被用來當并發地執行多個函數,開發人員現在不得不仔細地構建應用來支持這種并發。 多線程編程知識也因此在多核系統時代變得越來越重要。 本章將介紹C++ Boost庫 [Boost.Thread](http://www.boost.org/libs/thread/),它可以開發獨立于平臺的多線程應用程序。 ## 6.2.?線程管理 在這個庫最重要的一個類就是 `boost::thread`,它是在 `boost/thread.hpp` 里定義的,用來創建一個新線程。下面的示例來說明如何運用它。 ``` #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } void thread() { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << std::endl; } } int main() { boost::thread t(thread); t.join(); } ``` * [下載源代碼](src/6.2.1/main.cpp) 新建線程里執行的那個函數的名稱被傳遞到 `boost::thread` 的構造函數。 一旦上述示例中的變量 `t` 被創建,該 `thread()` 函數就在其所在線程中被立即執行。 同時在 `main()` 里也并發地執行該 `thread()` 。 為了防止程序終止,就需要對新建線程調用 `join()` 方法。 `join()` 方法是一個阻塞調用:它可以暫停當前線程,直到調用 `join()` 的線程運行結束。 這就使得 `main()` 函數一直會等待到 `thread()` 運行結束。 正如在上面的例子中看到,一個特定的線程可以通過諸如 `t` 的變量訪問,通過這個變量等待著它的使用 `join()` 方法終止。 但是,即使 `t` 越界或者析構了,該線程也將繼續執行。 一個線程總是在一開始就綁定到一個類型為 `boost::thread` 的變量,但是一旦創建,就不在取決于它。 甚至還存在著一個叫 `detach()` 的方法,允許類型為 `boost::thread` 的變量從它對應的線程里分離。 當然了,像 `join()` 的方法之后也就不能被調用,因為這個變量不再是一個有效的線程。 任何一個函數內可以做的事情也可以在一個線程內完成。 歸根結底,一個線程只不過是一個函數,除了它是同時執行的。 在上述例子中,使用一個循環把5個數字寫入標準輸出流。 為了減緩輸出,每一個循環中調用 `wait()` 函數讓執行延遲了一秒。 `wait()` 可以調用一個名為 `sleep()` 的函數,這個函數也來自于 Boost.Thread,位于 `boost::this_thread` 名空間內。 `sleep()` 要么在預計的一段時間或一個特定的時間點后時才讓線程繼續執行。 通過傳遞一個類型為 `boost::posix_time::seconds` 的對象,在這個例子里我們指定了一段時間。 `boost::posix_time::seconds` 來自于 Boost.DateTime 庫,它被 Boost.Thread 用來管理和處理時間的數據。 雖然前面的例子說明了如何等待一個不同的線程,但下面的例子演示了如何通過所謂的中斷點讓一個線程中斷。 ``` #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } void thread() { try { for (int i = 0; i < 5; ++i) { wait(1); std::cout << i << std::endl; } } catch (boost::thread_interrupted&) { } } int main() { boost::thread t(thread); wait(3); t.interrupt(); t.join(); } ``` * [下載源代碼](src/6.2.2/main.cpp) 在一個線程對象上調用 `interrupt()` 會中斷相應的線程。 在這方面,中斷意味著一個類型為 `boost::thread_interrupted` 的異常,它會在這個線程中拋出。 然后這只有在線程達到中斷點時才會發生。 如果給定的線程不包含任何中斷點,簡單調用 `interrupt()` 就不會起作用。 每當一個線程中斷點,它就會檢查 `interrupt()` 是否被調用過。 只有被調用過了, `boost::thread_interrupted` 異常才會相應地拋出。 Boost.Thread定義了一系列的中斷點,例如 `sleep()` 函數。 由于 `sleep()` 在這個例子里被調用了五次,該線程就檢查了五次它是否應該被中斷。 然而 `sleep()` 之間的調用,卻不能使線程中斷。 一旦該程序被執行,它只會打印三個數字到標準輸出流。 這是由于在main里3秒后調用 `interrupt()`方法。 因此,相應的線程被中斷,并拋出一個 `boost::thread_interrupted` 異常。 這個異常在線程內也被正確地捕獲, `catch` 處理雖然是空的。 由于 `thread()` 函數在處理程序后返回,線程也被終止。 這反過來也將終止整個程序,因為 `main()` 等待該線程使用join()終止該線程。 Boost.Thread定義包括上述 `sleep()`函數十個中斷。 有了這些中斷點,線程可以很容易及時中斷。 然而,他們并不總是最佳的選擇,因為中斷點必須事前讀入以檢查 `boost::thread_interrupted` 異常。 為了提供一個對 Boost.Thread 里提供的多種函數的整體概述,下面的例子將會再介紹兩個。 ``` #include <boost/thread.hpp> #include <iostream> int main() { std::cout << boost::this_thread::get_id() << std::endl; std::cout << boost::thread::hardware_concurrency() << std::endl; } ``` * [下載源代碼](src/6.2.3/main.cpp) 使用 `boost::this_thread`命名空間,能提供獨立的函數應用于當前線程,比如前面出現的 `sleep()` 。 另一個是 `get_id()`:它會返回一個當前線程的ID號。 它也是由 `boost::thread` 提供的。 `boost::thread` 類提供了一個靜態方法 `hardware_concurrency()` ,它能夠返回基于CPU數目或者CPU內核數目的刻在同時在物理機器上運行的線程數。 在常用的雙核機器上調用這個方法,返回值為2。 這樣的話就可以確定在一個多核程序可以同時運行的理論最大線程數。 ## 6.3.?同步 雖然多線程的使用可以提高應用程序的性能,但也增加了復雜性。 如果使用線程在同一時間執行幾個函數,訪問共享資源時必須相應地同步。 一旦應用達到了一定規模,這涉及相當一些工作。 本段介紹了Boost.Thread提供同步線程的類。 ``` #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } boost::mutex mutex; void thread() { for (int i = 0; i < 5; ++i) { wait(1); mutex.lock(); std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl; mutex.unlock(); } } int main() { boost::thread t1(thread); boost::thread t2(thread); t1.join(); t2.join(); } ``` * [下載源代碼](src/6.3.1/main.cpp) 多線程程序使用所謂的互斥對象來同步。 Boost.Thread提供多個的互斥類,`boost::mutex`是最簡單的一個。 互斥的基本原則是當一個特定的線程擁有資源的時候防止其他線程奪取其所有權。 一旦釋放,其他的線程可以取得所有權。 這將導致線程等待至另一個線程完成處理一些操作,從而相應地釋放互斥對象的所有權。 上面的示例使用一個類型為 `boost::mutex` 的 `mutex` 全局互斥對象。 `thread()` 函數獲取此對象的所有權才在 `for` 循環內使用 `lock()` 方法寫入到標準輸出流的。 一旦信息被寫入,使用 `unlock()` 方法釋放所有權。 `main()` 創建兩個線程,同時執行 `thread ()`函數。 利用 `for` 循環,每個線程數到5,用一個迭代器寫一條消息到標準輸出流。 不幸的是,標準輸出流是一個全局性的被所有線程共享的對象。 該標準不提供任何保證 `std::cout` 可以安全地從多個線程訪問。 因此,訪問標準輸出流必須同步:在任何時候,只有一個線程可以訪問 `std::cout`。 由于兩個線程試圖在寫入標準輸出流前獲得互斥體,實際上只能保證一次只有一個線程訪問 `std::cout`。 不管哪個線程成功調用 `lock()` 方法,其他所有線程必須等待,直到 `unlock()` 被調用。 獲取和釋放互斥體是一個典型的模式,是由Boost.Thread通過不同的數據類型支持。 例如,不直接地調用 `lock()` 和 `unlock()`,使用 `boost::lock_guard` 類也是可以的。 ``` #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } boost::mutex mutex; void thread() { for (int i = 0; i < 5; ++i) { wait(1); boost::lock_guard<boost::mutex> lock(mutex); std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl; } } int main() { boost::thread t1(thread); boost::thread t2(thread); t1.join(); t2.join(); } ``` * [下載源代碼](src/6.3.2/main.cpp) `boost::lock_guard` 在其內部構造和析構函數分別自動調用 `lock()` 和 `unlock()` 。 訪問共享資源是需要同步的,因為它顯示地被兩個方法調用。 `boost::lock_guard` 類是另一個出現在 [第?2?章 _智能指針_](smartpointers.html "第?2?章?智能指針") 的RAII用語。 除了`boost::mutex` 和 `boost::lock_guard` 之外,Boost.Thread也提供其他的類支持各種同步。 其中一個重要的就是 `boost::unique_lock` ,相比較 `boost::lock_guard` 而言,它提供許多有用的方法。 ``` #include <boost/thread.hpp> #include <iostream> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } boost::timed_mutex mutex; void thread() { for (int i = 0; i < 5; ++i) { wait(1); boost::unique_lock<boost::timed_mutex> lock(mutex, boost::try_to_lock); if (!lock.owns_lock()) lock.timed_lock(boost::get_system_time() + boost::posix_time::seconds(1)); std::cout << "Thread " << boost::this_thread::get_id() << ": " << i << std::endl; boost::timed_mutex *m = lock.release(); m->unlock(); } } int main() { boost::thread t1(thread); boost::thread t2(thread); t1.join(); t2.join(); } ``` * [下載源代碼](src/6.3.3/main.cpp) 上面的例子用不同的方法來演示 `boost::unique_lock` 的功能。 當然了,這些功能的用法對給定的情景不一定適用;`boost::lock_guard` 在上個例子的用法還是挺合理的。 這個例子就是為了演示 `boost::unique_lock` 提供的功能。 `boost::unique_lock` 通過多個構造函數來提供不同的方式獲得互斥體。 這個期望獲得互斥體的函數簡單地調用了 `lock()` 方法,一直等到獲得這個互斥體。 所以它的行為跟 `boost::lock_guard` 的那個是一樣的。 如果第二個參數傳入一個 `boost::try_to_lock` 類型的值,對應的構造函數就會調用 `try_lock()` 方法。 這個方法返回 `bool` 型的值:如果能夠獲得互斥體則返回`true`,否則返回 `false` 。 相比 `lock()` 函數,`try_lock()` 會立即返回,而且在獲得互斥體之前不會被阻塞。 上面的程序向 `boost::unique_lock` 的構造函數的第二個參數傳入`boost::try_to_lock`。 然后通過 `owns_lock()` 可以檢查是否可獲得互斥體。 如果不能, `owns_lock()` 返回 `false`。 這也用到 `boost::unique_lock` 提供的另外一個函數: `timed_lock()` 等待一定的時間以獲得互斥體。 給定的程序等待長達1秒,應較足夠的時間來獲取更多的互斥。 其實這個例子顯示了三個方法獲取一個互斥體:`lock()` 會一直等待,直到獲得一個互斥體。 `try_lock()` 則不會等待,但如果它只會在互斥體可用的時候才能獲得,否則返回 `false` 。 最后,`timed_lock()` 試圖獲得在一定的時間內獲取互斥體。 和 `try_lock()` 一樣,返回`bool` 類型的值意味著成功是否。 雖然 `boost::mutex` 提供了 `lock()` 和 `try_lock()` 兩個方法,但是 `boost::timed_mutex` 只支持 `timed_lock()` ,這就是上面示例那么使用的原因。 如果不用 `timed_lock()` 的話,也可以像以前的例子那樣用 `boost::mutex`。 就像 `boost::lock_guard` 一樣, `boost::unique_lock` 的析構函數也會相應地釋放互斥量。此外,可以手動地用 `unlock()` 釋放互斥量。也可以像上面的例子那樣,通過調用 `release()` 解除`boost::unique_lock` 和互斥量之間的關聯。然而在這種情況下,必須顯式地調用 `unlock()` 方法來釋放互斥量,因為 `boost::unique_lock` 的析構函數不再做這件事情。 `boost::unique_lock` 這個所謂的獨占鎖意味著一個互斥量同時只能被一個線程獲取。 其他線程必須等待,直到互斥體再次被釋放。 除了獨占鎖,還有非獨占鎖。 Boost.Thread里有個 `boost::shared_lock` 的類提供了非獨占鎖。 正如下面的例子,這個類必須和 `boost::shared_mutex` 型的互斥量一起使用。 ``` #include <boost/thread.hpp> #include <iostream> #include <vector> #include <cstdlib> #include <ctime> void wait(int seconds) { boost::this_thread::sleep(boost::posix_time::seconds(seconds)); } boost::shared_mutex mutex; std::vector<int> random_numbers; void fill() { std::srand(static_cast<unsigned int>(std::time(0))); for (int i = 0; i < 3; ++i) { boost::unique_lock<boost::shared_mutex> lock(mutex); random_numbers.push_back(std::rand()); lock.unlock(); wait(1); } } void print() { for (int i = 0; i < 3; ++i) { wait(1); boost::shared_lock<boost::shared_mutex> lock(mutex); std::cout << random_numbers.back() << std::endl; } } int sum = 0; void count() { for (int i = 0; i < 3; ++i) { wait(1); boost::shared_lock<boost::shared_mutex> lock(mutex); sum += random_numbers.back(); } } int main() { boost::thread t1(fill); boost::thread t2(print); boost::thread t3(count); t1.join(); t2.join(); t3.join(); std::cout << "Sum: " << sum << std::endl; } ``` * [下載源代碼](src/6.3.4/main.cpp) `boost::shared_lock` 類型的非獨占鎖可以在線程只對某個資源讀訪問的情況下使用。 一個線程修改的資源需要寫訪問,因此需要一個獨占鎖。 這樣做也很明顯:只需要讀訪問的線程不需要知道同一時間其他線程是否訪問。 因此非獨占鎖可以共享一個互斥體。 在給定的例子, `print()` 和 `count()` 都可以只讀訪問 `random_numbers` 。 雖然 `print()` 函數把 `random_numbers` 里的最后一個數寫到標準輸出,`count()` 函數把它統計到 `sum` 變量。 由于沒有函數修改 `random_numbers`,所有的都可以在同一時間用 `boost::shared_lock` 類型的非獨占鎖訪問它。 在 `fill()` 函數里,需要用一個 `boost::unique_lock` 類型的非獨占鎖,因為它插入了一個新的隨機數到 `random_numbers`。 在 `unlock()` 顯式地調用 `unlock()` 來釋放互斥量之后, `fill()` 等待了一秒。 相比于之前的那個樣子, 在 `for` 循環的尾部調用 `wait()` 以保證容器里至少存在一個隨機數,可以被`print()` 或者 `count()` 訪問。 對應地,這兩個函數在 `for` 循環的開始調用了 `wait()` 。 考慮到在不同的地方每個單獨地調用 `wait()` ,一個潛在的問題變得很明顯:函數調用的順序直接受CPU執行每個獨立進程的順序決定。 利用所謂的條件變量,可以同步哪些獨立的線程,使數組的每個元素都被不同的線程立即添加到 `random_numbers` 。 ``` #include <boost/thread.hpp> #include <iostream> #include <vector> #include <cstdlib> #include <ctime> boost::mutex mutex; boost::condition_variable_any cond; std::vector<int> random_numbers; void fill() { std::srand(static_cast<unsigned int>(std::time(0))); for (int i = 0; i < 3; ++i) { boost::unique_lock<boost::mutex> lock(mutex); random_numbers.push_back(std::rand()); cond.notify_all(); cond.wait(mutex); } } void print() { std::size_t next_size = 1; for (int i = 0; i < 3; ++i) { boost::unique_lock<boost::mutex> lock(mutex); while (random_numbers.size() != next_size) cond.wait(mutex); std::cout << random_numbers.back() << std::endl; ++next_size; cond.notify_all(); } } int main() { boost::thread t1(fill); boost::thread t2(print); t1.join(); t2.join(); } ``` * [下載源代碼](src/6.3.5/main.cpp) 這個例子的程序刪除了 `wait()` 和 `count()` 。線程不用在每個循環迭代中等待一秒,而是盡可能快地執行。此外,沒有計算總額;數字完全寫入標準輸出流。 為確保正確地處理隨機數,需要一個允許檢查多個線程之間特定條件的條件變量來同步不每個獨立的線程。 正如上面所說, `fill()` 函數用在每個迭代產生一個隨機數,然后放在 `random_numbers` 容器中。 為了防止其他線程同時訪問這個容器,就要相應得使用一個排它鎖。 不是等待一秒,實際上這個例子卻用了一個條件變量。 調用 `notify_all()` 會喚醒每個哪些正在分別通過調用`wait()` 等待此通知的線程。 通過查看 `print()` 函數里的 `for` 循環,可以看到相同的條件變量被 `wait()` 函數調用了。 如果這個線程被 `notify_all()` 喚醒,它就會試圖這個互斥量,但只有在 `fill()` 函數完全釋放之后才能成功。 這里的竅門就是調用 `wait()` 會釋放相應的被參數傳入的互斥量。 在調用 `notify_all()`后, `fill()` 函數會通過 `wait()` 相應地釋放線程。 然后它會阻止和等待其他的線程調用 `notify_all()` ,一旦隨機數已寫入標準輸出流,這就會在 `print()` 里發生。 注意到在 `print()` 函數里調用 `wait()` 事實上發生在一個單獨 `while` 循環里。 這樣做的目的是為了處理在 `print()` 函數里第一次調用 `wait()` 函數之前隨機數已經放到容器里。 通過比較 `random_numbers` 里元素的數目與預期值,發現這成功地處理了把隨機數寫入到標準輸出流。 ## 6.4.?線程本地存儲 線程本地存儲(TLS)是一個只能由一個線程訪問的專門的存儲區域。 TLS的變量可以被看作是一個只對某個特定線程而非整個程序可見的全局變量。 下面的例子顯示了這些變量的好處。 ``` #include <boost/thread.hpp> #include <iostream> #include <cstdlib> #include <ctime> void init_number_generator() { static bool done = false; if (!done) { done = true; std::srand(static_cast<unsigned int>(std::time(0))); } } boost::mutex mutex; void random_number_generator() { init_number_generator(); int i = std::rand(); boost::lock_guard<boost::mutex> lock(mutex); std::cout << i << std::endl; } int main() { boost::thread t[3]; for (int i = 0; i < 3; ++i) t[i] = boost::thread(random_number_generator); for (int i = 0; i < 3; ++i) t[i].join(); } ``` * [下載源代碼](src/6.4.1/main.cpp) 該示例創建三個線程,每個線程寫一個隨機數到標準輸出流。 `random_number_generator()` 函數將會利用在C++標準里定義的 `std::rand()` 函數創建一個隨機數。 但是用于 `std::rand()` 的隨機數產生器必須先用 `std::srand()` 正確地初始化。 如果沒做,程序始終打印同一個隨機數。 隨機數產生器,通過 `std::time()` 返回當前時間, 在 `init_number_generator()` 函數里完成初始化。 由于這個值每次都不同,可以保證產生器總是用不同的值初始化,從而產生不同的隨機數。 因為產生器只要初始化一次, `init_number_generator()` 用了一個靜態變量 `done` 作為條件量。 如果程序運行了多次,寫入的三分之二的隨機數顯然就會相同。 事實上這個程序有個缺陷:`std::rand()` 所用的產生器必須被各個線程初始化。 因此 `init_number_generator()` 的實現實際上是不對的,因為它只調用了一次 `std::srand()` 。使用TLS,這一缺陷可以得到糾正。 ``` #include <boost/thread.hpp> #include <iostream> #include <cstdlib> #include <ctime> void init_number_generator() { static boost::thread_specific_ptr<bool> tls; if (!tls.get()) tls.reset(new bool(false)); if (!*tls) { *tls = true; std::srand(static_cast<unsigned int>(std::time(0))); } } boost::mutex mutex; void random_number_generator() { init_number_generator(); int i = std::rand(); boost::lock_guard<boost::mutex> lock(mutex); std::cout << i << std::endl; } int main() { boost::thread t[3]; for (int i = 0; i < 3; ++i) t[i] = boost::thread(random_number_generator); for (int i = 0; i < 3; ++i) t[i].join(); } ``` * [下載源代碼](src/6.4.2/main.cpp) 用一個TLS變量 `tls` 代替靜態變量 `done`,是基于用 `bool` 類型實例化的 `boost::thread_specific_ptr` 。 原則上, `tls` 工作起來就像 `done` :它可以作為一個條件指明隨機數發生器是否被初始化。 但是關鍵的區別,就是 `tls` 存儲的值只對相應的線程可見和可用。 一旦一個 `boost::thread_specific_ptr` 型的變量被創建,它可以相應地設置。 不過,它期望得到一個 `bool` 型變量的地址,而非它本身。使用 `reset()` 方法,可以把它的地址保存到 `tls` 里面。 在給出的例子中,會動態地分配一個 `bool` 型的變量,由 `new` 返回它的地址,并保存到 `tls` 里。 為了避免每次調用 `init_number_generator()` 都設置 `tls` ,它會通過 `get()` 函數檢查是否已經保存了一個地址。 由于 `boost::thread_specific_ptr` 保存了一個地址,它的行為就像一個普通的指針。 因此,`operator*()` 和 `operator-&gt;()` 都被被重載以方便使用。 這個例子用 `*tls` 檢查這個條件當前是 `true` 還是 `false`。 再根據當前的條件,隨機數生成器決定是否初始化。 正如所見, `boost::thread_specific_ptr` 允許為當前進程保存一個對象的地址,然后只允許當前進程獲得這個地址。 然而,當一個線程已經成功保存這個地址,其他的線程就會可能就失敗。 如果程序正在執行時,它可能會令人感到奇怪:盡管有了TLS的變量,生成的隨機數仍然相等。 這是因為,三個線程在同一時間被創建,從而造成隨機數生成器在同一時間初始化。 如果該程序執行了幾次,隨機數就會改變,這就表明生成器初始化正確了。 ## 6.5.?練習 You can buy [solutions to all exercises](http://en.highscore.de/shop/index.php?p=boost-solution) in this book as a ZIP file. 1. 重構下面的程序用兩個線程來計算總和。由于現在許多處理器有兩個內核,應利用線程減少執行時間。 ``` #include &lt;boost/date_time/posix_time/posix_time.hpp&gt; #include &lt;boost/cstdint.hpp&gt; #include &lt;iostream&gt; int main() { boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time(); boost::uint64_t sum = 0; for (int i = 0; i &lt; 1000000000; ++i) sum += i; boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time(); std::cout &lt;&lt; end - start &lt;&lt; std::endl; std::cout &lt;&lt; sum &lt;&lt; std::endl; } ``` * [下載源代碼](src/6.5.1/main.cpp) 2. 通過利用處理器盡可能同時執行多的線程,把例1一般化。 例如,如果處理器有四個內核,就應該利用四個線程。 3. 修改下面的程序,在 `main()`中自己的線程中執行 `thread()` 。 程序應該能夠計算總和,然后把結果輸入到標準輸出兩次。 但可以更改 `calculate()`,`print()` 和 `thread()` 的實現,每個函數的接口仍需保持一致。 也就是說每個函數應該仍然沒有任何參數,也不需要返回一個值。 ``` #include &lt;iostream&gt; int sum = 0; void calculate() { for (int i = 0; i &lt; 1000; ++i) sum += i; } void print() { std::cout &lt;&lt; sum &lt;&lt; std::endl; } void thread() { calculate(); print(); } int main() { thread(); } ``` * [下載源代碼](src/6.5.2/main.cpp)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看