├── .gitignore ├── README.md ├── make_all.sh └── src ├── 01_hello_thread.cpp ├── 02_lambda_thread.cpp ├── 02_thread.cpp ├── 03_thread_argument.cpp ├── 04_thread_self_manage.cpp ├── 05_call_once.cpp ├── 06_naive_multithread.cpp ├── 07_mutex_lock.cpp ├── 08_improved_mutex_lock.cpp ├── 09_deadlock_bank_transfer.cpp ├── 10_improved_bank_transfer.cpp ├── 11_bank_transfer_wait_notify.cpp ├── 12_async_task.cpp ├── 13_packaged_task.cpp ├── 14_promise_future.cpp ├── 15_parallel_algorithm.cpp └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | # Thumbnails 10 | ._* 11 | 12 | # Files that might appear in the root of a volume 13 | .DocumentRevisions-V100 14 | .fseventsd 15 | .Spotlight-V100 16 | .TemporaryItems 17 | .Trashes 18 | .VolumeIcon.icns 19 | .com.apple.timemachine.donotpresent 20 | 21 | # Directories potentially created on remote AFP share 22 | .AppleDB 23 | .AppleDesktop 24 | Network Trash Folder 25 | Temporary Items 26 | .apdisk 27 | 28 | # bin 29 | bin 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Source code for [C++ 并发编程](https://paul.pub/cpp-concurrency/) -------------------------------------------------------------------------------- /make_all.sh: -------------------------------------------------------------------------------- 1 | rm -rf bin 2 | 3 | mkdir build 4 | cd build 5 | 6 | cmake ../src/ 7 | make 8 | 9 | cd ../ 10 | mv build/bin ./ 11 | rm -rf build/ 12 | -------------------------------------------------------------------------------- /src/01_hello_thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void hello() { 7 | cout << "Hello World from new thread." << endl; 8 | } 9 | 10 | int main() { 11 | thread t(hello); 12 | t.join(); 13 | 14 | return 0; 15 | } -------------------------------------------------------------------------------- /src/02_lambda_thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | thread t([] { 8 | cout << "Hello World from lambda thread." << endl; 9 | }); 10 | 11 | t.join(); 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /src/02_thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static const int MAX = 10e8; 10 | 11 | static mutex gMutex; 12 | 13 | static double sum = 0; 14 | 15 | void worker(int min, int max) { 16 | for (int i = min; i <= max; i++) { 17 | sum += sqrt(i); 18 | } 19 | } 20 | 21 | void serial_task(int min, int max) { 22 | auto start_time = chrono::steady_clock::now(); 23 | sum = 0; 24 | worker(0, MAX); 25 | auto end_time = chrono::steady_clock::now(); 26 | auto ms = chrono::duration_cast(end_time - start_time).count(); 27 | cout << "Serail task finish, " << ms << " ms consumed, Result: " << sum << endl; 28 | } 29 | 30 | void concurrent_worker(int min, int max) { 31 | { 32 | lock_guard guard(gMutex); 33 | cout << "Thread " << this_thread::get_id() << " work for [" << min << ", " << max << "]" << endl; 34 | } 35 | double cur_sum = 0; 36 | for (int i = min; i <= max; i++) { 37 | cur_sum += sqrt(i); 38 | } 39 | { 40 | lock_guard guard(gMutex); 41 | sum += cur_sum; 42 | } 43 | } 44 | 45 | void concurrent_task(int min, int max) { 46 | auto start_time = chrono::steady_clock::now(); 47 | 48 | unsigned concurrent_count = thread::hardware_concurrency(); 49 | cout << "hardware_concurrency: " << concurrent_count << endl; 50 | vector threads; 51 | min = 0; 52 | sum = 0; 53 | for (int t = 0; t < concurrent_count; t++) { 54 | int range = max / concurrent_count * (t + 1); 55 | threads.push_back(thread(concurrent_worker, min, range)); 56 | min = range + 1; 57 | } 58 | for (int i = 0; i < threads.size(); i++) { 59 | threads[i].join(); 60 | } 61 | 62 | auto end_time = chrono::steady_clock::now(); 63 | auto ms = chrono::duration_cast(end_time - start_time).count(); 64 | cout << "Concurrent task finish, " << ms << " ms consumed, Result: " << sum << endl; 65 | } 66 | 67 | int main() { 68 | serial_task(0, MAX); 69 | concurrent_task(0, MAX); 70 | return 0; 71 | } -------------------------------------------------------------------------------- /src/03_thread_argument.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void hello(string name) { 8 | cout << "Welcome to " << name << endl; 9 | } 10 | 11 | int main() { 12 | thread t(hello, "https://paul.pub"); 13 | t.join(); 14 | 15 | return 0; 16 | } -------------------------------------------------------------------------------- /src/04_thread_self_manage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void print_time() { 11 | auto now = chrono::system_clock::now(); 12 | auto in_time_t = chrono::system_clock::to_time_t(now); 13 | 14 | std::stringstream ss; 15 | ss << put_time(localtime(&in_time_t), "%Y-%m-%d %X"); 16 | cout << "now is: " << ss.str() << endl; 17 | } 18 | 19 | void sleep_thread() { 20 | this_thread::sleep_for(chrono::seconds(3)); 21 | cout << "[thread-" << this_thread::get_id() << "] is waking up" << endl; 22 | } 23 | 24 | void loop_thread() { 25 | for (int i = 0; i < 10; i++) { 26 | cout << "[thread-" << this_thread::get_id() << "] print: " << i << endl; 27 | } 28 | } 29 | 30 | int main() { 31 | print_time(); 32 | 33 | thread t1(sleep_thread); 34 | thread t2(loop_thread); 35 | 36 | t1.join(); 37 | t2.detach(); 38 | 39 | print_time(); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /src/05_call_once.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void init() { 8 | cout << "Initialing..." << endl; 9 | // Do something... 10 | } 11 | 12 | void worker(once_flag* flag) { 13 | call_once(*flag, init); 14 | } 15 | 16 | int main() { 17 | once_flag flag; 18 | 19 | thread t1(worker, &flag); 20 | thread t2(worker, &flag); 21 | thread t3(worker, &flag); 22 | 23 | t1.join(); 24 | t2.join(); 25 | t3.join(); 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /src/06_naive_multithread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static const int MAX = 10e8; 10 | static double sum = 0; 11 | 12 | void worker(int min, int max) { 13 | for (int i = min; i <= max; i++) { 14 | sum += sqrt(i); 15 | } 16 | } 17 | 18 | void serial_task(int min, int max) { 19 | auto start_time = chrono::steady_clock::now(); 20 | sum = 0; 21 | worker(0, MAX); 22 | auto end_time = chrono::steady_clock::now(); 23 | auto ms = chrono::duration_cast(end_time - start_time).count(); 24 | cout << "Serail task finish, " << ms << " ms consumed, Result: " << sum << endl; 25 | } 26 | 27 | void concurrent_task(int min, int max) { 28 | auto start_time = chrono::steady_clock::now(); 29 | 30 | unsigned concurrent_count = thread::hardware_concurrency(); 31 | cout << "hardware_concurrency: " << concurrent_count << endl; 32 | vector threads; 33 | min = 0; 34 | sum = 0; 35 | for (int t = 0; t < concurrent_count; t++) { 36 | int range = max / concurrent_count * (t + 1); 37 | threads.push_back(thread(worker, min, range)); 38 | min = range + 1; 39 | } 40 | for (int i = 0; i < threads.size(); i++) { 41 | threads[i].join(); 42 | } 43 | 44 | auto end_time = chrono::steady_clock::now(); 45 | auto ms = chrono::duration_cast(end_time - start_time).count(); 46 | cout << "Concurrent task finish, " << ms << " ms consumed, Result: " << sum << endl; 47 | } 48 | 49 | int main() { 50 | serial_task(0, MAX); 51 | concurrent_task(0, MAX); 52 | return 0; 53 | } -------------------------------------------------------------------------------- /src/07_mutex_lock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | static const int MAX = 10e8; 11 | static double sum = 0; 12 | 13 | static mutex exclusive; 14 | 15 | void concurrent_worker(int min, int max) { 16 | for (int i = min; i <= max; i++) { 17 | exclusive.lock(); 18 | sum += sqrt(i); 19 | exclusive.unlock(); 20 | } 21 | } 22 | 23 | void concurrent_task(int min, int max) { 24 | auto start_time = chrono::steady_clock::now(); 25 | 26 | unsigned concurrent_count = thread::hardware_concurrency(); 27 | cout << "hardware_concurrency: " << concurrent_count << endl; 28 | vector threads; 29 | min = 0; 30 | sum = 0; 31 | for (int t = 0; t < concurrent_count; t++) { 32 | int range = max / concurrent_count * (t + 1); 33 | threads.push_back(thread(concurrent_worker, min, range)); 34 | min = range + 1; 35 | } 36 | for (int i = 0; i < threads.size(); i++) { 37 | threads[i].join(); 38 | } 39 | 40 | auto end_time = chrono::steady_clock::now(); 41 | auto ms = chrono::duration_cast(end_time - start_time).count(); 42 | cout << "Concurrent task finish, " << ms << " ms consumed, Result: " << sum << endl; 43 | } 44 | 45 | int main() { 46 | concurrent_task(0, MAX); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/08_improved_mutex_lock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | static const int MAX = 10e8; 11 | static double sum = 0; 12 | 13 | static mutex exclusive; 14 | 15 | void concurrent_worker(int min, int max) { 16 | double tmp_sum = 0; 17 | for (int i = min; i <= max; i++) { 18 | tmp_sum += sqrt(i); 19 | } 20 | exclusive.lock(); 21 | sum += tmp_sum; 22 | exclusive.unlock(); 23 | } 24 | 25 | void concurrent_task(int min, int max) { 26 | auto start_time = chrono::steady_clock::now(); 27 | 28 | unsigned concurrent_count = thread::hardware_concurrency(); 29 | cout << "hardware_concurrency: " << concurrent_count << endl; 30 | vector threads; 31 | min = 0; 32 | sum = 0; 33 | for (int t = 0; t < concurrent_count; t++) { 34 | int range = max / concurrent_count * (t + 1); 35 | threads.push_back(thread(concurrent_worker, min, range)); 36 | min = range + 1; 37 | } 38 | for (int i = 0; i < threads.size(); i++) { 39 | threads[i].join(); 40 | } 41 | 42 | auto end_time = chrono::steady_clock::now(); 43 | auto ms = chrono::duration_cast(end_time - start_time).count(); 44 | cout << "Concurrent task finish, " << ms << " ms consumed, Result: " << sum << endl; 45 | } 46 | 47 | int main() { 48 | concurrent_task(0, MAX); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /src/09_deadlock_bank_transfer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | class Account { 9 | public: 10 | Account(string name, double money): mName(name), mMoney(money) {}; 11 | 12 | public: 13 | void changeMoney(double amount) { 14 | mMoney += amount; 15 | } 16 | string getName() { 17 | return mName; 18 | } 19 | double getMoney() { 20 | return mMoney; 21 | } 22 | mutex* getLock() { 23 | return &mMoneyLock; 24 | } 25 | 26 | private: 27 | string mName; 28 | double mMoney; 29 | mutex mMoneyLock; 30 | }; 31 | 32 | class Bank { 33 | public: 34 | void addAccount(Account* account) { 35 | mAccounts.insert(account); 36 | } 37 | 38 | bool transferMoney(Account* accountA, Account* accountB, double amount) { 39 | lock_guard guardA(*accountA->getLock()); 40 | lock_guard guardB(*accountB->getLock()); 41 | 42 | if (amount > accountA->getMoney()) { 43 | return false; 44 | } 45 | 46 | accountA->changeMoney(-amount); 47 | accountB->changeMoney(amount); 48 | return true; 49 | } 50 | 51 | double totalMoney() const { 52 | double sum = 0; 53 | for (auto a : mAccounts) { 54 | sum += a->getMoney(); 55 | } 56 | return sum; 57 | } 58 | 59 | private: 60 | set mAccounts; 61 | }; 62 | 63 | void randomTransfer(Bank* bank, Account* accountA, Account* accountB) { 64 | while(true) { 65 | double randomMoney = ((double)rand() / RAND_MAX) * 100; 66 | if (bank->transferMoney(accountA, accountB, randomMoney)) { 67 | cout << "Transfer " << randomMoney << " from " << accountA->getName() 68 | << " to " << accountB->getName() 69 | << ", Bank totalMoney: " << bank->totalMoney() << endl; 70 | } else { 71 | cout << "Transfer failed, " 72 | << accountA->getName() << " has only $" << accountA->getMoney() << ", but " 73 | << randomMoney << " required" << endl; 74 | } 75 | } 76 | } 77 | 78 | int main() { 79 | Account a("Paul", 100); 80 | Account b("Moira", 100); 81 | 82 | Bank aBank; 83 | aBank.addAccount(&a); 84 | aBank.addAccount(&b); 85 | 86 | thread t1(randomTransfer, &aBank, &a, &b); 87 | thread t2(randomTransfer, &aBank, &b, &a); 88 | 89 | t1.join(); 90 | t2.join(); 91 | 92 | return 0; 93 | } -------------------------------------------------------------------------------- /src/10_improved_bank_transfer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | class Account { 9 | public: 10 | Account(string name, double money): mName(name), mMoney(money) {}; 11 | 12 | public: 13 | void changeMoney(double amount) { 14 | mMoney += amount; 15 | } 16 | string getName() { 17 | return mName; 18 | } 19 | double getMoney() { 20 | return mMoney; 21 | } 22 | mutex* getLock() { 23 | return &mMoneyLock; 24 | } 25 | 26 | private: 27 | string mName; 28 | double mMoney; 29 | mutex mMoneyLock; 30 | }; 31 | 32 | class Bank { 33 | public: 34 | void addAccount(Account* account) { 35 | mAccounts.insert(account); 36 | } 37 | 38 | bool transferMoney(Account* accountA, Account* accountB, double amount) { 39 | // lock(*accountA->getLock(), *accountB->getLock()); 40 | // lock_guard lockA(*accountA->getLock(), adopt_lock); 41 | // lock_guard lockB(*accountB->getLock(), adopt_lock); 42 | 43 | scoped_lock lockAll(*accountA->getLock(), *accountB->getLock()); 44 | 45 | if (amount > accountA->getMoney()) { 46 | return false; 47 | } 48 | 49 | accountA->changeMoney(-amount); 50 | accountB->changeMoney(amount); 51 | return true; 52 | } 53 | 54 | double totalMoney() const { 55 | double sum = 0; 56 | for (auto a : mAccounts) { 57 | sum += a->getMoney(); 58 | } 59 | return sum; 60 | } 61 | 62 | private: 63 | set mAccounts; 64 | }; 65 | 66 | mutex sCoutLock; 67 | void randomTransfer(Bank* bank, Account* accountA, Account* accountB) { 68 | while(true) { 69 | double randomMoney = ((double)rand() / RAND_MAX) * 100; 70 | if (bank->transferMoney(accountA, accountB, randomMoney)) { 71 | sCoutLock.lock(); 72 | cout << "Transfer " << randomMoney << " from " << accountA->getName() 73 | << " to " << accountB->getName() 74 | << ", Bank totalMoney: " << bank->totalMoney() << endl; 75 | sCoutLock.unlock(); 76 | } else { 77 | sCoutLock.lock(); 78 | cout << "Transfer failed, " 79 | << accountA->getName() << " has only " << accountA->getMoney() << ", but " 80 | << randomMoney << " required" << endl; 81 | sCoutLock.unlock(); 82 | } 83 | } 84 | } 85 | 86 | int main() { 87 | Account a("Paul", 100); 88 | Account b("Moira", 100); 89 | 90 | Bank aBank; 91 | aBank.addAccount(&a); 92 | aBank.addAccount(&b); 93 | 94 | thread t1(randomTransfer, &aBank, &a, &b); 95 | thread t2(randomTransfer, &aBank, &b, &a); 96 | 97 | t1.join(); 98 | t2.join(); 99 | 100 | return 0; 101 | } -------------------------------------------------------------------------------- /src/11_bank_transfer_wait_notify.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Account { 10 | public: 11 | Account(string name, double money): mName(name), mMoney(money) {}; 12 | 13 | public: 14 | void changeMoney(double amount) { 15 | unique_lock lock(mMoneyLock); 16 | mConditionVar.wait(lock, [this, amount] { 17 | return mMoney + amount > 0; 18 | }); 19 | mMoney += amount; 20 | mConditionVar.notify_all(); 21 | } 22 | 23 | string getName() { 24 | return mName; 25 | } 26 | 27 | double getMoney() { 28 | return mMoney; 29 | } 30 | 31 | private: 32 | string mName; 33 | double mMoney; 34 | mutex mMoneyLock; 35 | condition_variable mConditionVar; 36 | }; 37 | 38 | class Bank { 39 | public: 40 | void addAccount(Account* account) { 41 | mAccounts.insert(account); 42 | } 43 | 44 | void transferMoney(Account* accountA, Account* accountB, double amount) { 45 | accountA->changeMoney(-amount); 46 | accountB->changeMoney(amount); 47 | } 48 | 49 | double totalMoney() const { 50 | double sum = 0; 51 | for (auto a : mAccounts) { 52 | sum += a->getMoney(); 53 | } 54 | return sum; 55 | } 56 | 57 | private: 58 | set mAccounts; 59 | }; 60 | 61 | mutex sCoutLock; 62 | void randomTransfer(Bank* bank, Account* accountA, Account* accountB) { 63 | while(true) { 64 | double randomMoney = ((double)rand() / RAND_MAX) * 100; 65 | { 66 | lock_guard guard(sCoutLock); 67 | cout << "Try to Transfer " << randomMoney 68 | << " from " << accountA->getName() << "(" << accountA->getMoney() 69 | << ") to " << accountB->getName() << "(" << accountB->getMoney() 70 | << "), Bank totalMoney: " << bank->totalMoney() << endl; 71 | } 72 | bank->transferMoney(accountA, accountB, randomMoney); 73 | } 74 | } 75 | 76 | int main() { 77 | Account a("Paul", 100); 78 | Account b("Moira", 100); 79 | 80 | Bank aBank; 81 | aBank.addAccount(&a); 82 | aBank.addAccount(&b); 83 | 84 | thread t1(randomTransfer, &aBank, &a, &b); 85 | thread t2(randomTransfer, &aBank, &b, &a); 86 | 87 | t1.join(); 88 | t2.join(); 89 | 90 | return 0; 91 | } -------------------------------------------------------------------------------- /src/12_async_task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static const int MAX = 10e8; 10 | static double sum = 0; 11 | 12 | void worker(int min, int max) { 13 | for (int i = min; i <= max; i++) { 14 | sum += sqrt(i); 15 | } 16 | } 17 | 18 | class Worker { 19 | public: 20 | Worker(int min, int max): mMin(min), mMax(max) {} 21 | double work() { 22 | mResult = 0; 23 | for (int i = mMin; i <= mMax; i++) { 24 | mResult += sqrt(i); 25 | } 26 | return mResult; 27 | } 28 | double getResult() { 29 | return mResult; 30 | } 31 | 32 | private: 33 | int mMin; 34 | int mMax; 35 | double mResult; 36 | }; 37 | 38 | int main() { 39 | sum = 0; 40 | auto f1 = async(worker, 0, MAX); 41 | cout << "Async task triggered" << endl; 42 | f1.wait(); 43 | cout << "Async task finish, result: " << sum << endl << endl; 44 | 45 | double result = 0; 46 | cout << "Async task with lambda triggered, thread: " << this_thread::get_id() << endl; 47 | auto f2 = async(launch::async, [&result]() { 48 | cout << "Lambda task in thread: " << this_thread::get_id() << endl; 49 | for (int i = 0; i <= MAX; i++) { 50 | result += sqrt(i); 51 | } 52 | }); 53 | f2.wait(); 54 | cout << "Async task with lambda finish, result: " << result << endl << endl; 55 | 56 | Worker w(0, MAX); 57 | cout << "Task in class triggered" << endl; 58 | auto f3 = async(&Worker::work, &w); 59 | f3.wait(); 60 | cout << "Task in class finish, result: " << w.getResult() << endl << endl; 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /src/13_packaged_task.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static const int MAX = 10e8; 10 | 11 | double concurrent_worker(int min, int max) { 12 | double sum = 0; 13 | for (int i = min; i <= max; i++) { 14 | sum += sqrt(i); 15 | } 16 | return sum; 17 | } 18 | 19 | double concurrent_task(int min, int max) { 20 | vector> results; 21 | 22 | unsigned concurrent_count = thread::hardware_concurrency(); 23 | min = 0; 24 | for (int i = 0; i < concurrent_count; i++) { 25 | packaged_task task(concurrent_worker); 26 | results.push_back(task.get_future()); 27 | 28 | int range = max / concurrent_count * (i + 1); 29 | thread t(std::move(task), min, range); 30 | t.detach(); 31 | 32 | min = range + 1; 33 | } 34 | 35 | cout << "threads create finish" << endl; 36 | double sum = 0; 37 | for (auto& r : results) { 38 | sum += r.get(); 39 | } 40 | return sum; 41 | } 42 | 43 | int main() { 44 | auto start_time = chrono::steady_clock::now(); 45 | 46 | double r = concurrent_task(0, MAX); 47 | 48 | auto end_time = chrono::steady_clock::now(); 49 | auto ms = chrono::duration_cast(end_time - start_time).count(); 50 | cout << "Concurrent task finish, " << ms << " ms consumed, Result: " << r << endl; 51 | return 0; 52 | } -------------------------------------------------------------------------------- /src/14_promise_future.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | static const int MAX = 10e8; 10 | 11 | double concurrent_worker(int min, int max) { 12 | double sum = 0; 13 | for (int i = min; i <= max; i++) { 14 | sum += sqrt(i); 15 | } 16 | return sum; 17 | } 18 | 19 | void concurrent_task(int min, int max, promise* result) { 20 | vector> results; 21 | 22 | unsigned concurrent_count = thread::hardware_concurrency(); 23 | min = 0; 24 | for (int i = 0; i < concurrent_count; i++) { 25 | packaged_task task(concurrent_worker); 26 | results.push_back(task.get_future()); 27 | 28 | int range = max / concurrent_count * (i + 1); 29 | thread t(std::move(task), min, range); 30 | t.detach(); 31 | 32 | min = range + 1; 33 | } 34 | 35 | cout << "threads create finish" << endl; 36 | double sum = 0; 37 | for (auto& r : results) { 38 | sum += r.get(); 39 | } 40 | result->set_value(sum); 41 | cout << "concurrent_task finish" << endl; 42 | } 43 | 44 | int main() { 45 | auto start_time = chrono::steady_clock::now(); 46 | 47 | promise sum; 48 | concurrent_task(0, MAX, &sum); 49 | 50 | auto end_time = chrono::steady_clock::now(); 51 | auto ms = chrono::duration_cast(end_time - start_time).count(); 52 | cout << "Concurrent task finish, " << ms << " ms consumed." << endl; 53 | cout << "Result: " << sum.get_future().get() << endl; 54 | return 0; 55 | } -------------------------------------------------------------------------------- /src/15_parallel_algorithm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void generateRandomData(vector& collection, int size) { 11 | random_device rd; 12 | mt19937 mt(rd()); 13 | uniform_real_distribution dist(1.0, 100.0); 14 | for (int i = 0; i < size; i++) { 15 | collection.push_back(dist(mt)); 16 | } 17 | } 18 | 19 | int main() { 20 | vector collection; 21 | generateRandomData(collection, 10e6); 22 | 23 | vector copy1(collection); 24 | vector copy2(collection); 25 | vector copy3(collection); 26 | 27 | auto time1 = chrono::steady_clock::now(); 28 | sort(execution::seq, copy1.begin(), copy1.end()); 29 | auto time2 = chrono::steady_clock::now(); 30 | auto duration = chrono::duration_cast(time2 - time1).count(); 31 | cout << "Sequenced sort consuming " << duration << "ms." << endl; 32 | 33 | auto time3 = chrono::steady_clock::now(); 34 | sort(execution::par, copy2.begin(),copy2.end()); 35 | auto time4 = chrono::steady_clock::now(); 36 | duration = chrono::duration_cast(time4 - time3).count(); 37 | cout << "Parallel sort consuming " << duration << "ms." << endl; 38 | 39 | auto time5 = chrono::steady_clock::now(); 40 | sort(execution::par_unseq, copy2.begin(),copy2.end()); 41 | auto time6 = chrono::steady_clock::now(); 42 | duration = chrono::duration_cast(time6 - time5).count(); 43 | cout << "Parallel unsequenced sort consuming " << duration << "ms." << endl; 44 | } -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.8) 2 | project(cpp-concurrency) 3 | 4 | set(CMAKE_CXX_COMPILER "g++-9") 5 | set(CMAKE_CXX_STANDARD 17) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ./bin) 9 | 10 | add_executable(hello_thread 01_hello_thread.cpp) 11 | add_executable(lambda_thread 02_lambda_thread.cpp) 12 | add_executable(thread_argument 03_thread_argument.cpp) 13 | add_executable(thread_self_manage 04_thread_self_manage.cpp) 14 | add_executable(call_once 05_call_once.cpp) 15 | add_executable(naive_multithread 06_naive_multithread.cpp) 16 | add_executable(mutex_lock 07_mutex_lock.cpp) 17 | add_executable(improved_mutex_lock 08_improved_mutex_lock.cpp) 18 | add_executable(deadlock_bank_transfer 09_deadlock_bank_transfer.cpp) 19 | add_executable(improved_bank_transfer 10_improved_bank_transfer.cpp) 20 | add_executable(bank_transfer_wait_notify 11_bank_transfer_wait_notify.cpp) 21 | add_executable(async_task 12_async_task.cpp) 22 | add_executable(packaged_task 13_packaged_task.cpp) 23 | add_executable(promise_future 14_promise_future.cpp) 24 | 25 | # For OS X 26 | if(APPLE) 27 | if (DEFINED ENV{tbb_path}) 28 | message("tbb_path=" $ENV{tbb_path}) 29 | include_directories($ENV{tbb_path}/include/) 30 | link_directories($ENV{tbb_path}/lib/) 31 | add_executable(parallel_algorithm 15_parallel_algorithm.cpp) 32 | target_link_libraries(parallel_algorithm tbb) 33 | else() 34 | message("[Warning] 'tbb_path' not defined, 'export tbb_path=xxx' to build parallel algorithm.") 35 | endif() 36 | endif() 37 | 38 | # For Linux 39 | IF("${CMAKE_SYSTEM}" MATCHES "Linux") 40 | add_executable(parallel_algorithm 15_parallel_algorithm.cpp) 41 | target_link_libraries(parallel_algorithm tbb) 42 | target_link_libraries(hello_thread pthread) 43 | target_link_libraries(lambda_thread pthread) 44 | target_link_libraries(thread_argument pthread) 45 | target_link_libraries(thread_self_manage pthread) 46 | target_link_libraries(call_once pthread) 47 | target_link_libraries(naive_multithread pthread) 48 | target_link_libraries(mutex_lock pthread) 49 | target_link_libraries(improved_mutex_lock pthread) 50 | target_link_libraries(deadlock_bank_transfer pthread) 51 | target_link_libraries(improved_bank_transfer pthread) 52 | target_link_libraries(bank_transfer_wait_notify pthread) 53 | target_link_libraries(async_task pthread) 54 | target_link_libraries(packaged_task pthread) 55 | target_link_libraries(promise_future pthread) 56 | endif() 57 | 58 | --------------------------------------------------------------------------------