我的程式中有 2 個執行緒:
- 從鍵盤接收輸入
- 計算一些數學
- 輸出結果
DWORD WINAPI F1(LPVOID lpParameter)
{
// std::cin >> data
// calculate
return 0;
}
DWORD WINAPI F2(LPVOID lpParameter)
{
// std::cin >> data
// calculate
return 0;
}
int main()
{
thread_handles[0] = CreateThread(NULL,
0,
F1,
NULL,
0,
NULL);
assert(thread_handles[0] != NULL);
thread_handles[1] = CreateThread(NULL,
0,
F2,
NULL,
0,
NULL);
assert(thread_handles[1] != NULL);
WaitForMultipleObjects(THREADS_COUNT,
thread_handles,
TRUE,
INFINITE);
CloseHandle(thread_handles[0]);
CloseHandle(thread_handles[1]);
return 0;
}
但是當我運行我的程式時,它們都同時從終端讀取輸入。如何將它們一一填充然后并行計算?
uj5u.com熱心網友回復:
您正在尋找的模式稱為生產者-消費者
您應該通過一個執行緒(生產者)將資料讀入某個記憶體,然后與一個或多個執行緒(消費者)共享此記憶體。每個消費者執行他們的計算。
例如,原始的 WinAPI(執行緒池 API)可用于實作消費者,而不是通過對執行緒進行分組來重新發明輪子。
同樣,C 標準庫也可用于其執行緒 API。
以下示例要求用戶輸入兩個整數向量,然后并行計算它們的總和。這里的主應用執行緒是一個生產者,其中執行緒池,即執行緒組,是消費者。
#include <windows.h>
#include <numeric>
#include <vector>
#include <iostream>
// those to just for demonstrating C standard library API for solving same problem
#include <atomic>
#include <thread>
// utility function to read count integers from console user input into vector
void read_ints_to_vec(std::vector<int>& to, std::size_t count)
{
int v = 0;
for(std::size_t i=0; i < count; i ) {
std::cin >> v;
to.emplace_back( v );
}
}
// utility function to pretty print the vector
template<typename iterator_type>
void print_iterable(const iterator_type& begin,const iterator_type& end)
{
if(begin != end) {
auto it = begin;
std::cout << "{ " << *it;
while( it != end) {
std::cout << ", ";
std::cout << *it;
}
std::cout << " } ";
}
}
// Prints last system error into system error stream in case of any OS error
int print_last_error()
{
::DWORD ret =::GetLastError();
if( NO_ERROR != ret ) {
wchar_t msg[512];
::DWORD len = ::FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, ret,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(::LPWSTR) &msg,
256, NULL );
::DWORD written;
if( !::WriteFile( ::GetStdHandle(STD_ERROR_HANDLE), msg, len, &written, nullptr ) ) {
MessageBoxExW(NULL, msg, NULL, MB_OK | MB_ICONERROR, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) );
}
}
return ret;
}
// Returns number of system logical CPUs i.e. cores threads
unsigned int hardware_concurrency()
{
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
}
// this is a context i.e. message to be passed from
// producer main thread to consumer
struct vector_sum_context {
const std::vector<int>* v;
intmax_t sum;
};
// this is thread pull routine i.e. consumer task calculating sum of integers vector
void CALLBACK sum_vector_routine(PTP_CALLBACK_INSTANCE,PVOID context,PTP_WORK)
{
auto ctx = static_cast< vector_sum_context* >(context);
ctx->sum = std::accumulate(ctx->v->cbegin(), ctx->v->cend(), 0);
}
int main(int argc, const char** argv)
{
std::vector<int> v0, v1;
std::cout << "Please input first vector of 4 integers to sum them " << std::endl;
read_ints_to_vec(v0, 4);
std::cout << "Please input second vector of 4 integers to sum them " << std::endl;
read_ints_to_vec(v1, 4);
/* create thread pull */
PTP_POOL tp = ::CreateThreadpool(nullptr);
if(nullptr == tp)
return print_last_error();
if( FALSE == ::SetThreadpoolThreadMinimum(tp, 1) ) {
::CloseThreadpool(tp);
return print_last_error();
}
SetThreadpoolThreadMaximum(tp, hardware_concurrency());
PTP_CLEANUP_GROUP cleanup_group = ::CreateThreadpoolCleanupGroup();
if(nullptr == cleanup_group) {
CloseThreadpool(tp);
return print_last_error();
}
TP_CALLBACK_ENVIRON cbenv;
InitializeThreadpoolEnvironment(&cbenv);
SetThreadpoolCallbackCleanupGroup(&cbenv, cleanup_group, [](PVOID, PVOID) {});
/* Now submit two tasks into our thread pull */
vector_sum_context c0 {&v0, 0};
PTP_WORK work0 = ::CreateThreadpoolWork(sum_vector_routine, &c0, &cbenv);
SubmitThreadpoolWork(work0);
vector_sum_context c1 {&v1, 0};
PTP_WORK work1 = ::CreateThreadpoolWork(sum_vector_routine, &c1, &cbenv);
SubmitThreadpoolWork(work1);
/*
join thread pool
i.e. wait until all asynchronous operations to accomplish
*/
CloseThreadpoolCleanupGroupMembers(cleanup_group, FALSE, nullptr);
/* Clean up the cleanup group and close thread poll */
CloseThreadpoolCleanupGroup(cleanup_group);
DestroyThreadpoolEnvironment(&cbenv);
CloseThreadpool(tp);
// Display results
std::cout << "Sums calculated by windows thread pool" << std::endl;
std::cout << "Vector 0 ";
print_iterable(v0.cbegin(), v0.cend());
std::cout << " sum = " << c0.sum << std::endl;
std::cout << "Vector 1 ";
print_iterable(v1.cbegin(), v1.cend());
std::cout << " sum = " << c1.sum << std::endl;
// Same thing implemented with C standard library
std::atomic_intmax_t sum0 = 0, sum1 = 0;
std::thread t0( [&v0, &sum0] { sum0.store( std::accumulate(v0.cbegin(), v0.cend(), 0) ); } );
std::thread t1( [&v1, &sum1] { sum1.store( std::accumulate(v1.cbegin(), v1.cend(), 0) ); } );
t0.join();
t1.join();
std::cout << "Sums calculated by C thread API" << std::endl;
std::cout << "Vector 0 ";
print_iterable(v0.cbegin(), v0.cend());
std::cout << " sum =" << sum0.load() << std::endl;
std::cout << "Vector 1 ";
print_iterable(v1.cbegin(), v1.cend());
std::cout << " sum =" << sum1.load() << std::endl;
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/510141.html
標籤:C温纳皮
上一篇:如何在C#.Net中呼叫asmx服務而不添加服務參考
下一篇:將虛擬檔案復制到剪貼板
