I noticed that the second loop in this code will always execute much faster than the first. Why is that?
int main()
{
float t1 = -1, t2 = -1;
Timer timer(&t1);
for (int i = 0; i < 10000; i++)
{
std::cout << i << '\n';
}
timer.End();
Timer timer2(&t2);
for (int i = 0; i < 10000; i++)
{
std::cout << i << '\n';
}
timer2.End();
std::cout << "t1 = " << t1 << "ms\n";
std::cout << "t2 = " << t2 << "ms\n";
}
Output:
t1 = 6251.83ms
t2 = 2492.48ms
Related
#include <iostream>
#include <future>
auto gClock = clock();
char threadPool(char c) {
std::cout << "enter thread :" << c << " cost time:" << clock() - gClock << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
for (int i = 0; i < 10; i++)
std::cout << c;
std::cout << std::endl;
return c;
}
void fnTestAsync(){
auto begin = clock();
std::future<char> futures[10];
for (int i = 0; i < 10; ++i){
futures[i] = std::async(std::launch::async,threadPool, 'a' + i);
}
for (int i = 0; i < 10; ++i){
std::cout << futures[i].get() << " back ,cost time: " << clock() - begin << std::endl;
}
std::cout << "fnTestAsync: " << clock() - begin << std::endl;
}
int main(){
std::thread testAsync(fnTestAsync);
testAsync.detach();
std::this_thread::sleep_for(std::chrono::seconds(10));
return 0;
}
run result
I'm trying to get these 10 threads to execute together and all return immediately after a two second delay, but I output the time spent and find that it takes about 2900ms, much larger than the 2000ms I expected.
What is the cause of this increase?
How should he fix it?
I am attemtping to access and pop the front element from a queue in C++, but the line
tuple<int, string, future<string>> post = posterVerificationQueue.front();
is underlined in red and gives the error:
function "std::tuple<_This, _Rest...>::tuple(const std::tuple<_This,
_Rest...> &) [with _This=int, _Rest=<std::string, std::futurestd::string>]" (declared at line 320 of "C:\Program Files
(x86)\Microsoft Visual
Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\tuple") cannot
be referenced -- it is a deleted function
I imagine it is an issue with me using a future within a tuple, but not too sure. Here is my code:
#include <iostream>
#include <ctime>
#include <chrono>
#include <thread>
#include <future>
#include <queue>
#include <mutex>
#include <tuple>
#include <map>
#include "TCPClient.h"
#include "ThreadPool.h"
#include "RequestGenerator.h"
#include "ResponseVerifier.h"
#include "Storage.h"
#define DEFAULT_PORT 12345
void readRequest(string serverIp, int threadIndex, double timeDurationSecs);
void postRequest(string serverIp, int threadIndex, double timeDurationSecs);
int readRequests = 0;
int postRequests = 0;
mutex mLock;
map<int, tuple<double, int>> posterThreadMap;
queue<tuple<int, string, future<string>>> posterVerificationQueue;
map<int, tuple<double, int>> readerThreadMap;
Storage* db = new Storage();
RequestGenerator* requestGenerator = new RequestGenerator();
int main(int argc, char **argv)
{
// Default parameters
unsigned int posterCount = 5;
unsigned int readerCount = 0;
double timeDurationSecs = 10;
bool throttle = false;
string serverIp = "127.0.0.1";
// Validate the parameters
if (argc != 6) {
std::cout << "\nUsage (required parameters): server_IP number_of_poster_threads number_of_reader_threads time_duration throttle(0|1)\n\n";
std::cout << "server_IP - IP of the server\n";
std::cout << "number_of_poster_threads - number of threads performing POST operations\n";
std::cout << "number_of_reader_threads - number of threads performing READ operations\n";
std::cout << "time_duration - duration of test execution in seconds\n";
std::cout << "throttle(0|1) - 0: do not throttle message speed\n";
std::cout << "\t\t1: throttle message speed\n\n";
std::cout << "\nDefault Parameters:\n";
std::cout << "\tserver_IP - " << serverIp << "\n";
std::cout << "\tnumber_of_poster_threads - " << posterCount << "\n";
std::cout << "\tnumber_of_reader_threads - " << readerCount << "\n";
std::cout << "\ttime_duration - " << timeDurationSecs << "s\n";
std::cout << "\tthrottle - " << (throttle ? "true" : "false") << "\n\n";
std::cout << "Enter dev mode using default paramaters?\n";
system("pause");
}
else
{
serverIp = argv[1];
posterCount = (int)argv[2];
readerCount = (int)argv[3];
timeDurationSecs = (int)argv[4];
throttle = (int)argv[5];
}
cout << "\nStarting throughput test...\n";
ThreadPool posterPool(posterCount);
vector<future<void>> posterFutures;
vector<tuple<string, int, int>> incorrectPostResponses;
double posterTotalTime = 0.0; // The total time in seconds that all poster threads took to run
ThreadPool readerPool(readerCount);
vector<future<void>> readerFutures;
double readerTotalTime = 0.0; // The total time in seconds that all reader threads took to run
for (int i = 0; i < posterCount; i++)
posterFutures.push_back(posterPool.enqueue(postRequest, serverIp, i, timeDurationSecs));
for (int i = 0; i < readerCount; i++)
readerFutures.push_back(readerPool.enqueue(readRequest, serverIp, i, timeDurationSecs));
for (int i = 0; i < posterFutures.size(); i++)
posterFutures[i].wait();
for (int i = 0; i < readerFutures.size(); i++)
readerFutures[i].wait();
for (int i = 0; i < posterThreadMap.size(); i++)
{
double posterRequestsPerSecond = get<1>(posterThreadMap[i]);
double threadRunTime = get<0>(posterThreadMap[i]);
posterTotalTime += threadRunTime;
std::cout << "\nPoster thread " << i << " (ran for " << threadRunTime << "s) - Average post requests per second: " << posterRequestsPerSecond << "\n";
}
// Should verification be optional?
while (!posterVerificationQueue.empty())
{
tuple<int, string, future<string>> post = posterVerificationQueue.front();
posterVerificationQueue.pop();
int postIndex = get<0>(post);
string request = get<1>(post);
string response = get<2>(post).get();
tuple<bool, int, int> postVerification = db->addPosterValue(postIndex, request, response);
bool isValid = get<0>(postVerification);
if (!isValid)
{
int correctResponse = get<1>(postVerification);
int actualResponse = get<2>(postVerification);
incorrectPostResponses.push_back(make_tuple(request, correctResponse, actualResponse));
}
}
cout << "\nTotal poster runtime: " << posterTotalTime << "s" << "\n";
cout << "\nTotal post requests: " << postRequests << "\n";
cout << "\nAverage post requests per second per thread: " << postRequests / posterTotalTime << "\n";
cout << "\nIncorrect responses: " << incorrectPostResponses.size() << "\n";
for (int i = 0; i < incorrectPostResponses.size(); i++)
{
tuple<string, int, int> incorrectResponse = incorrectPostResponses[i];
string request = get<0>(incorrectResponse);
int correctResponse = get<1>(incorrectResponse);
int actualResponse = get<2>(incorrectResponse);
cout << "Incorrect response #" << i + 1 << "\n";
cout << "Request: " << request << "\n";
cout << "Expected response: " << correctResponse << "\n";
cout << "Actual response: " << actualResponse << "\n\n";
}
// TODO: Implement the block above for reader threads
delete db;
delete requestGenerator;
system("pause");
return 0;
}
string sendRequest(TCPClient client, string request)
{
return client.send(request);
}
void postRequest(string serverIp, int threadIndex, double timeDurationSecs)
{
TCPClient client(serverIp, DEFAULT_PORT);
client.OpenConnection();
int threadPostCount = 0;
double timeSpan;
chrono::high_resolution_clock::time_point endTime;
chrono::high_resolution_clock::time_point startTime = chrono::high_resolution_clock::now();
do
{
/*
Could limit with
if (!throttle || (throttle && threadPostCount < (timeDurationSecs * 1000)))
{}
*/
string request = requestGenerator->generateWriteRequest();
mLock.lock();
future<string> responseFut = async(launch::async, sendRequest, client, request);
posterVerificationQueue.push(make_tuple(postRequests, request, move(responseFut)));
postRequests++;
mLock.unlock();
threadPostCount++;
endTime = chrono::high_resolution_clock::now();
timeSpan = chrono::duration_cast<chrono::duration<double>>(endTime - startTime).count();
} while (timeSpan < timeDurationSecs);
double totalRunTime = (endTime - startTime).count();
double posterRequestsPerSecond = threadPostCount / timeSpan;
tuple<double, double> returnValues = make_tuple(timeSpan, posterRequestsPerSecond);
mLock.lock();
postRequests += threadPostCount;
posterThreadMap[threadIndex] = returnValues;
mLock.unlock();
client.CloseConnection();
}
void readRequest(string serverIp, int threadIndex, double timeDurationSecs)
{
//return 0.0;
}
std::tuple<_This, _Rest...>::tuple(const std::tuple<_This, _Rest...> &)
...
cannot be referenced -- it is a deleted function
Well, that's the tuple copy constructor, right?
I imagine it is an issue with me using a future within a tuple, but not too sure.
Let's check the documentation for the constructors of std::future ...
future( const future& other ) = delete;
std::future is not CopyConstructible.
So I'd say your imagination was correct. You can't copy the tuple, because it can't copy one of its members.
You can use std::move to move construct from the queue element, but remember it would be a problem if you didn't pop the front immediately after (in the code shown, you do this, so it's fine).
I'm new to C++. In my application, there is a method getOnlineStatus():
int getOnlineStatus(int num);
This method is from third party DLL, it can't be modified.
I call this method to check number status, like this:
int num = 123456;
for (int i = 0; i < 10000000; i++) {
num = num + 1;
int nRet = getOnlineStatus(num);
if (nRet > 0) {
cout << num << "status online" << endl;
}
else if (nRet == 0) {
cout << num << "status offline" << endl;
}
else {
cout << num << "check fail" << endl;
}
}
But every time, it will take 2 seconds to return the nRet. So, if I check lots of number, it will take a long time.
Also, I tried to use async, but it's not working, it still takes 2 seconds to return a result one by one.
int num = 123456;
for (int i = 0; i < 10000000; i++) {
num = num + 1;
future<int> fuRes = std::async(std::launch::async, getOnlineStatus, num);
int result = fuRes.get();
if (result > 0) {
cout << num << "status online" << endl;
}
else if (result == 0) {
cout << num << "status offline" << endl;
}
else {
cout << num << "check fail" << endl;
}
}
Is there any way to open multiple threads to make it show results faster?
This largely depends on your third party DLL - does it even support requests from multiple threads? And if it does - do those requests use shared resources? Like the same internet connection / socket?
If you simplify your question and assume that the getOnlineStatus() sleeps for 2 seconds - then yes, you can greatly benefit from issuing multiple requests on different threads and wait in parallel.
Here is how you can simply setup reasonable number of threads to share the workload:
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
int status[10'000]{};
int getOnlineStatus(int n) {
std::this_thread::sleep_for(std::chrono::seconds(1));
return rand();
}
void getStatus(int low, int high) {
for (int i = low; i < high; i++) {
status[i] = getOnlineStatus(i);
}
}
int main()
{
srand(0);
const int count = std::thread::hardware_concurrency();
auto start = std::chrono::high_resolution_clock::now();
std::vector<std::thread> threads;
for (int i = 0, low = 0, high = 10; i < count; ++i, low += 10, high += 10)
threads.emplace_back(std::thread(getStatus, low, high));
for (auto& thread : threads)
thread.join();
auto stop = std::chrono::high_resolution_clock::now();
std::cout << count << " threads: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << " ms" << std::endl;
start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 10 * count; ++i)
status[i] = getOnlineStatus(i);
stop = std::chrono::high_resolution_clock::now();
std::cout << "single thread: " << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << " ms" << std::endl;
}
I get this result:
12 threads: 10075 ms
single thread: 120720 ms
NOTE: if those worker threads really do nothing, you can run many more of those, reducing total time significantly.
I'm having an issue with a ranged based for loop causing my values to go negative, and I've resolved the issue with a regular for loop but want to understand why it messed up in the first place. You can see from the sample output below that the initial values exist correctly, but then when attempting to subtract from them, they get reset to a default initialized value of 0 I guess?
Broken code:
#include <iostream>
#include <vector>
#define IS_TRUE(x) { if (!(x)) std::cout << __FUNCTION__ << " failed on line " << __LINE__ << std::endl; }
int maximumScore(std::vector<int>& nums, std::vector<int>& multipliers) {
std::vector<int> multRank;
multRank.resize(multipliers.size());
std::cout << "multRank: ";
//ISSUE IS IN THE LOOP BELOW
for (int n : multRank) {
n = multipliers.size();
std::cout << " " << n;
}
std::cout << std::endl;
for (auto i = 0; i < multipliers.size(); ++i) {
for (auto j = 0; j < multipliers.size(); ++j) {
int abs1 = std::abs(multipliers[i]);
int abs2 = std::abs(multipliers[j]);
if (abs1 > abs2) {
multRank[i] = multRank[i] - 1;
std::cout << multRank[i];
}
}
}
std::cout << std::endl << "multRank after: ";
for (int n : multRank) {
std::cout << " " << n;
}
std::cout << std::endl << std::endl;
return 0;
}
void test1()
{
std::vector<int> nums = { 1, 2, 3 };
std::vector<int> multipliers = { 3, 2, 1 };
int test = maximumScore(nums, multipliers);
IS_TRUE(test == 14);
}
int main()
{
std::cout << "Maximum Score from Performing Multiplication Operations\n";
test1();
}
Broken code output:
Maximum Score from Performing Multiplication Operations
multRank: 3 3 3
-1-2-1
multRank after: -2 -1 0
Repaired code:
#include <iostream>
#include <vector>
#define IS_TRUE(x) { if (!(x)) std::cout << __FUNCTION__ << " failed on line " << __LINE__ << std::endl; }
int maximumScore(std::vector<int>& nums, std::vector<int>& multipliers) {
std::vector<int> multRank;
multRank.resize(multipliers.size());
std::cout << "multRank: ";
//ISSUE WAS IN THE LOOP BELOW
for (auto i = 0; i < multipliers.size(); ++i) {
multRank[i] = multipliers.size();
std::cout << " " << multRank[i];
}
std::cout << std::endl;
for (auto i = 0; i < multipliers.size(); ++i) {
for (auto j = 0; j < multipliers.size(); ++j) {
int abs1 = std::abs(multipliers[i]);
int abs2 = std::abs(multipliers[j]);
if (abs1 > abs2) {
multRank[i]--;
std::cout << multRank[i];
}
}
}
std::cout << std::endl << "multRank after: ";
for (int n : multRank) {
std::cout << " " << n;
}
std::cout << std::endl << std::endl;
return 0;
}
void test1()
{
std::vector<int> nums = { 1, 2, 3 };
std::vector<int> multipliers = { 3, 2, 1 };
int test = maximumScore(nums, multipliers);
IS_TRUE(test == 14);
}
int main()
{
std::cout << "Calculate Rank\n";
test1();
}
Repaired code output:
Maximum Score from Performing Multiplication Operations
multRank: 3 3 3
212
multRank after: 1 2 3
The first range based for loop is not using references:
for (int n : multRank) {
n = multipliers.size();
std::cout << " " << n;
}
In this loop, n is a copy of the data in multRank. If you want to be able to modify the data in multRank, you want n to be a reference:
for (int& n : multRank) {
n = multipliers.size();
std::cout << " " << n;
}
double x = 10;
boost::shared_mutex xSharedMutex;
void r() {
boost::shared_lock<boost::shared_mutex> lock(xSharedMutex);
for (int i = 0; i < 100; i++) {
cout << "**** READ **** " << x << endl;
usleep(200);
}
}
void w() {
boost::upgrade_lock<boost::shared_mutex> lock(xSharedMutex);
for (int i = 0; i < 100; i++) {
x = i + 12;
cout << "---- WRITE ---- " << x <<endl;
usleep(200);
}
}
int main() {
boost::thread t1(&r);
boost::thread t2(&w);
sleep(3);
}
I expect that read and write will go sequentially because of an upgrade_lock has been added in w(). However, the read and write run simutaneously.
Is the usage of shared_lock and upgrade_lock wrong? How to fix it? Thanks.
You need either unique ownership for writing:
boost::unique_lock<boost::shared_mutex> lock(xSharedMutex);
for (int i = 0; i < 100; i++) {
x = i + 12;
std::cout << "---- WRITE ---- " << x << std::endl;
usleep(200);
}
Or you can upgrade that lock ad-hoc:
upgrade_lock<shared_mutex> lock(xSharedMutex);
for (int i = 0; i < 100; i++) {
{
upgrade_to_unique_lock<shared_mutex> write_lock(lock);
x = i + 12;
std::cout << "---- WRITE ---- " << x << std::endl;
}
usleep(200);
}
Of course, the output in this program gets intermixed as the console output is not under any kind of lock (this is strictly UB)