Multithreading Timer and I/O in Console C++ - c++

I'm developing a game that has a word falling to the bottom of the screen and the user typing that word before it hits the bottom. So you'll be able to type input while the word is falling. Right now I have a timer that waits 5 seconds, prints the word, runs timer again, clears the screen, and prints the word down 10 units.
int main()
{
for (int i = 0; i < 6; i++)
{
movexy(x, y);
cout << "hello\n";
y = y + 10;
wordTimer();
}
}
Very basic I know. Which is why I thought multithreading would be a good idea so that way I could have the word falling while I still type input at the bottom. This is my attempt at that so far:
vector<std::thread> threads;
for (int i = 0; i < 5; ++i) {
threads.push_back(std::thread(task1, "hello\n"));
threads.push_back(std::thread(wordTimer));
}
for (auto& thread : threads) {
thread.join();
}
However this only prints hello 4 times to the screen, then prints 55, then prints hello again, then counts-down 3 more times. So any advice on how to correctly do this? I've already done research. Just a few of the links I checked out that didn't help:
Multithreaded console I/O
C++11 Multithreading: Display to console
Render Buffer on Screen in Windows
Threading console application in c++
Create new console from console app? C++
Console output from thread
https://msdn.microsoft.com/en-us/library/975t8ks0.aspx?f=255&MSPPError=-2147217396
http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm
EDIT:
Here is wordTimer()
int wordTimer()
{
_timeb start_time;
_timeb current_time;
_ftime_s(&start_time);
int i = 5;
for (; i > 0; i--)
{
cout << i << endl;
current_time = start_time;
while (elapsed_ms(&start_time, &current_time) < 1000)
{
_ftime_s(&current_time);
}
start_time = current_time;
}
cout << " 5 seconds have passed." << endl;
return 0;
}
this is also necessary for wordTimer()
unsigned int elapsed_ms(_timeb* start, _timeb* end)
{
return (end->millitm - start->millitm) + 1000 * (end->time - start->time);
}
and task1
void task1(string msg)
{
movexy(x, y);
cout << msg;
y = y + 10;
}
and void movexy(int x, int y)
void movexy(int column, int line)
{
COORD coord;
coord.X = column;
coord.Y = line;
SetConsoleCursorPosition(
GetStdHandle(STD_OUTPUT_HANDLE),
coord
);
}

Threads do not run in any particular order - the operating system can schedule them whenever it feels like it. Your code starts ten threads - five that print "Hello", and five that count down. So the most likely outcome is that your program will try to print "Hello" five times at the same time, and also count down five times at the same time.
If you want to do things in a particular order, don't do them all in separate threads. Just have one thread that does the things in the right order.

Related

Printing on specific parts of the terminal

So for my university homework we are supposed to make a simple game of a 2D map with entities etc.
So I've figured a way of printing a map through it's dimensions and text formatting yet in our lessons it wasn't mentioned how we print on specific parts of the terminal. I've checked same questions but can't seem to get a solution.
Here is the code I use to print the map and make it's array. BLUE_B,STANDARD_B,OUTLINE and GREEN_B are declared above for the sake of color enrichment. Also IF POSSIBLE I don't want to use OS specific commands unless it's completely necessary. I use VS Code for Windows, compile with g++ on WSL Ubuntu-20.04.
for (int row = 0; row < i; row++) {
cout << OUTLINE "##";
for (int column = 0; column < j; column++) {
int n = rand() % 10; // According to "rand()"'s value we print either green, blue, or trees
if (n >= 3) { // We've assigned more values to green, in order to be more possible to be printed
cout << GREEN_B " "
STANDARD_B;
map[row][column] = 1;
} else if (n == 0 || n == 1) {
cout << BLUE_B " "
STANDARD_B;
map[row][column] = 0;
} else if (n == 2) {
int tree = rand() % 2;
cout << TREES "<>"
STANDARD_B;
map[row][column] = 0;
}
}
cout << OUTLINE "##"
STANDARD_B << endl;
}
for (i = 0; i < j + 2; i++) { // Bottom map border printing
cout << OUTLINE "##"
STANDARD_B;
}
If I understand the question correctly, you might be looking for iomanip. It is just one way of doing it. You can use setw and setfill to position different text in different areas. You can set different options for different outputs.
To move the text cursor to a specific line and column you need a “gotoxy”-style function.
Here is something that will work on both Linux terminals and the Windows Terminal. (It will not work on Windows Console without additional initialization help.)
#include <iostream>
const char * CSI = "\033[";
void gotoxy( int x, int y )
{
std::cout << CSI << (y+1) << ";" << (x+1) << "H";
}
Coordinates are (0,0) for the UL corner of the terminal. Here is a working example of use:
// continuing from above
#include <string>
int main()
{
// Clear a 40 x 10 box
for (int y = 0; y < 10; y++)
{
gotoxy( 0, y );
std::cout << std::string( 40, ' ' );
}
// Draw our centered text
gotoxy( 14, 5 );
std::cout << "Hello there!";
// Go to bottom of box and terminate
gotoxy( 0, 10 );
std::cout.flush();
}
For your game
I suggest you move the cursor to HOME (0,0) and draw the changed parts of your gameboard each frame.
I suppose that if you are on a local computer and your gameboard is relatively simple, you could probably get away with a complete redraw each frame...
Are you sure there is no professor-supplied macro or command to move the cursor home? (...as he has supplied magic macros to change the output color)?

Adjusting the speed of 2 different object on console

I'm making a simple game like Google's Dinosaur Game. As you pass the obstacles, their speed increases as well as the Dino. What I wanna do is make Dino's speed constant while obstacles speed increases.
while (1)
{
if (GetAsyncKeyState(VK_SPACE) < 0 || action) // checking if the user press SPACE
{
if (!action) button = _getch();
if (button == VK_SPACE) // rest is making the dino move up and down.
{
action = 1;
if (loop < 6)
{
std::queue<Position> tempQue = dinoPos;
for (size_t i = 0; i < DINOSIZE; i++)
{
setCursor(dinoPos.front().x, dinoPos.front().y); dinoPos.pop();
std::cout << " ";
}
for (size_t i = 0; i < DINOSIZE; i++)
{
setCursor(tempQue.front().x, tempQue.front().y - 1);
tempQue.front().y -= 1;
dinoPos.push(tempQue.front());
tempQue.pop();
std::cout << "D";
}
}
loop++;
if (loop == 12)
{
loop = 0;
action = 0;
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(speed)); // using this for speeding up the game
You don't want to use sleep_for. It can sleep for longer and offers no timing guarantees. What you want it a fixed update game loop. You can look in popular game engines to see how it's implemented.
But it boils down to the following pseudo-code:
//mainloop
// get a number of frame based on time.
// take a number of frame higher than expected frame rate. say 10 ms.
int frame = now() / frameDuration;
while(true)
{
int frameNow = now() / frameDuration;
while(frame != frameNow)
{
Update();
frame++;
}
render();
}
With the following update function: (pseudo-code again)
// there, you advance you object for a fixing duration, say 10 ms.
// just use different speed for each
Update()
{
obstacle.position += obstacleSpeed * frameDuration;
character.position += characterSpeed * frameDuration;
}

Trouble with MPI Allgatherv function

I have been struggling to try to parallel this function which calculates interactions between particles. I had an idea to use Allgatherv which should distribute my original buffer to all other processes. Then using "rank" make a loop in which each process will calculate its part.In this program, MPI is overwritten to show stats that's why I am calling it mpi->function. Unfortunately, when I run it I receive following error. Can somebody advice what is wrong?
void calcInteraction() {
totalInteraction = 0.0;
int procs_number;
int rank;
int particle_amount = particles;
mpi->MPI_Comm_size(MPI_COMM_WORLD,&procs_number);
mpi->MPI_Comm_rank(MPI_COMM_WORLD,&rank);
//long sendBuffer[particle_amount];
//int *displs[procs_number];
//long send_counts[procs_number+mod];
int mod = (particle_amount%procs_number);
int elements_per_process = particle_amount/procs_number;
int *send_buffer = new int[particle_amount]; //data to send
int *displs = new int[procs_number]; //displacement
int *send_counts = new int[procs_number];
if(rank == 0)
{
for(int i = 0; i < particle_amount; i++)
{
send_buffer[i] = i; // filling buffer with particles
}
}
for (int i = 0; i < procs_number;i++)
{
send_counts[i] = elements_per_process; // filling buffer since it can't be empty
}
// calculating displacement
displs[ 0 ] = 0;
for ( int i = 1; i < procs_number; i++ )
displs[ i ] = displs[ i - 1 ] + send_counts[ i - 1 ];
int allData = displs[ procs_number - 1 ] + send_counts[ procs_number - 1 ];
int * endBuffer = new int[allData];
int start,end; // initializing indices
cout<<"entering allgather"<<endl;
mpi->MPI_Allgatherv(send_buffer,particle_amount,MPI_INT,endBuffer,send_counts,displs,MPI_INT,MPI_COMM_WORLD);
// ^from ^how many ^send ^receive ^how many ^displ ^send ^communicator
// to send type buffer receive type
start = rank*elements_per_process;
cout<<"start = "<< start <<endl;
if(rank == procs_number) //in case that particle_amount is not even
{
end = (rank+1)*elements_per_process + mod;
}
else
{
end = (rank+1)*elements_per_process;
}
cout<<"end = "<< end <<endl;
cout << "calcInteraction" << endl;
for (long idx = start; idx < end; idx++) {
for (long idxB = start; idxB < end; idxB++) {
if (idx != idxB) {
totalInteraction += physics->interaction(x[idx], y[idx], z[idx], age[idx], x[idxB], y[idxB],
z[idxB], age[idxB]);
}
}
}
cout << "calcInteraction - done" << endl;
}
You are not using MPI_Allgatherv() correctly.
I had an idea to use Allgatherv which should distribute my original
buffer to all other processes.
The description suggests you need MPI_Scatter[v]() in order to slice your array from a given rank, and distributes the chunks to all the MPI tasks.
If all tasks should receive the full array, then MPI_Bcast() is what you need.
Anyway, let's assume you need an all gather.
First, you must ensure all tasks have the same particles value.
Second, since you gather the same amout of data from every MPI tasks, and store them in a contiguous location, you can simplify your code with MPI_Allgather(). If only the last task might have a bit less data, then you can use MPI_Allgatherv() (but this is not what your code is currently doing) or transmit some ghost data so you can use the simple (and probably more optimized) MPI_Allgather().
Last but not least, you should send elements_per_process elements (and not particle_amount). That should be enough to get rid of the crash (e.g. MPI_ERR_TRUNCATE). But that being said, i am not sure that will achieve the result you need or expect.

Issues with \r and \n or Buffer Flushing

I have read in multiple places that \n does not flush the buffer when used however in my code, which I will add at the end of this question, it seems to be doing just that or at least it seems that way from the output (maybe something else is going on in the background due to how I am executing my couts?).
Expected Output:
Mining Laser 1 cycle will complete in x seconds...
Mining Laser 2 cycle will complete in x seconds...
Mining Laser 3 cycle will complete in x seconds...
Mining Laser 4 cycle will complete in x seconds...
What I Get in the CLI:
Mining Laser 1 cycle will complete in x seconds...
Mining Laser 2 cycle will complete in x seconds...
Mining Laser 3 cycle will complete in x seconds...
Mining Laser 4 cycle will complete in x seconds...
Mining Laser 1 cycle will complete in x seconds...
Mining Laser 2 cycle will complete in x seconds...
Mining Laser 3 cycle will complete in x seconds...
Mining Laser 4 cycle will complete in x seconds...
Mining Laser 1 cycle will complete in x seconds...
Mining Laser 2 cycle will complete in x seconds...
Mining Laser 3 cycle will complete in x seconds...
Mining Laser 4 cycle will complete in x seconds...
What I want the output to do is remain in place, like those in the expected output example, and just update itself every the time loop in my code executes.
Here is my code:
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>
using namespace std; //Tacky, but good enough fo a poc D:
class mLaser
{
public:
mLaser(int clen, float mamt, int time_left)
{
mlCLen = clen;
mlMAmt = mamt;
mCTime_left = time_left;
}
int getCLen()
{
return mlCLen;
}
float getMAmt()
{
return mlMAmt;
}
void setMCOld(int old)
{
mCTime_old = old;
}
void mCycle()
{
int mCTime_new = GetTickCount(); //Get current tick count for comparison to mCOld_time
if (mCTime_old != ((mCTime_new + 500) / 1000)) //Do calculations to see if time has passed since mCTime_old was set
{
//If it has then update mCTime_old and remove one second from mCTime_left.
mCTime_old = ((mCTime_new + 500) / 1000);
mCTime_left -= 1000;
}
cur_time = mCTime_left;
}
int getCTime()
{
return cur_time;
}
int getCTLeft()
{
return mCTime_left;
}
private:
int mlCLen; //Time of a complete mining cycle
float mlMAmt; //Amoung of ore produced by one mining cycle (not used yet)
int cur_time; //The current time remaining in the current mining cycle; will be removing this as it is just a copy of mCTime_left that I was going to use for another possiblity to make this code work
int mCTime_left; //The current time remaining in the current mining cycle
int mCTime_old; //The last time that mCycle was called
};
void sMCycle(mLaser& ml, int i1, thread& _thread); //Start a mining cycle thread
//Some global defines
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> laser(1, 3); //A random range for the number of mlaser entities to use
uniform_int_distribution<> cLRand(30, 90); //A random time range in seconds of mining cycle lengths
uniform_real_distribution<float> mARand(34.0f, 154.3f); //A random float range of the amount of ore produced by one mining cycle (not used yet)
int main()
{
//Init some variables for later use
vector<mLaser> mlasers; //Vector to hold mlaser objects
vector<thread> mthreads; //Vector to hold threads
vector<shared_future<int>> futr; //Vector to hold shared_futures (not used yet, might not be used if I can get the code working like this)
int lasers; //Number of lasers to create
int cycle_time; //Mining cycle time
int active_miners = 0; //Number of active mining cycle threads (one for each laser)
float mining_amount; //Amount of ore produced by one mining cycle (not used yet)
lasers = laser(gen); //Get a random number
active_miners = lasers; //Set this to that random number for the while loop later on
//Create the mlaser objects and push them into the mlasers vector
for (int i = 0; i < lasers; i++)
{
int clength = cLRand(gen);
mlasers.push_back(mLaser(clength, mARand(gen), (clength * 1000)));
//Also push thread obects into mthreads for each laser object
mthreads.push_back(thread());
}
//Setup data for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
int mCTime_start = GetTickCount(); //Get cycle start time
mlasers.at(i).setMCOld(((mCTime_start + 500) / 1000));
}
//Print initial display for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
cout << "Mining Laser " << i+1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
}
while (active_miners > 0)
{
for (int i = 0; i < mlasers.size(); i++)
{
//futr.push_back(async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }));
async(launch::async, [&mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }); //Launch a thread for the current mlaser object
//mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
}
//Output information from loops
cout << " \r" << flush; //Return cursor to start of line and flush the buffer for the next info
for (int i = 0; i < mlasers.size(); i++)
{
if ((mlasers.at(i).getCTLeft() != 0) //If mining cycle is not completed
{
cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds...\n";
}
else //If it is completed
{
cout << "Mining Laser " << i + 1 << " has completed its mining cycle!\n";
active_miners -= 1;
}
}
}
/*for (int i = 0; i < mthreads.size(); i++)
{
mthreads.at(i).join();
}*/
//string temp = futr.get();
//float out = strtof(temp.c_str(),NULL);
//cout << out << endl;
system("Pause");
return 0;
}
void sMCycle(mLaser& ml, int i1,thread& _thread)
{
//Start thread
_thread = thread(bind(&mLaser::mCycle, ref(ml)));
//Join the thread
_thread.join();
}
Per Ben Voigt, it seems that \r cannot be used in the way I am attempting to use it. Does anyone have any other suggestions apart from Matthew's suggestion of clsing the command window each update? Maybe something in Boost or something new to c++11?
Thanks.
You could try clearing the console after every execution
with something like system("cls");
here is a link to a post
[How can I clear console

Unexpected Output While Using Threads

I am working on a proof of concept test program for a game where certain actions are threaded and information is output to the command window for each thread. So far I have gotten the basic threading process to work but it seems that the couting in my called function is not being written for each thread and instead each thread is overwriting the others output.
The desired or expected output is that each thread will output the information couted within the mCycle function of mLaser. Essentially this is meant to be a timer of sorts for each object counting down the time until that object has completed its task. There should be an output for each thread, so if five threads are running there should be five counters counting down independently.
The current output is such that each thread is outputting its own information with in the same space which then overwrites what another thread is attempting to output.
Here is an example of the current output of the program:
Time until cycle Time until cycle 74 is complete: 36 is complete:
92 seconds 2 seconds ress any key to continue . . .
You can see the aberrations where numbers and other text are in places they should not be if you examine how the information is couted from mCycle.
What should be displayed is more long these lines:
Time until cycle 1 is complete:
92 seconds
Time until cycle 2 is complete:
112 seconds
Time until cycle 3 is complete:
34 seconds
Cycle 4 has completed!
I am not sure if this is due to some kind of thread locking going on due to how my code is structured or just an oversight in my coding for the output. If I could get a fresh pair of eyes to look over the code and point anything out that could be the fault I would appreciate it.
Here is my code, it should be compilable in any MSVS 2013 install (no custom libraries used)
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>
using namespace std;
class mLaser
{
public:
mLaser(int clen, float mamt)
{
mlCLen = clen;
mlMAmt = mamt;
}
int getCLen()
{
return mlCLen;
}
float getMAmt()
{
return mlMAmt;
}
void mCycle(int i1, int mCLength)
{
bool bMCycle = true;
int mCTime_left = mCLength * 1000;
int mCTime_start = GetTickCount(); //Get cycle start time
int mCTime_old = ((mCTime_start + 500) / 1000);
cout << "Time until cycle " << i1 << " is complete: " << endl;
while (bMCycle)
{
cout << ((mCTime_left + 500) / 1000) << " seconds";
bool bNChange = true;
while (bNChange)
{
//cout << ".";
int mCTime_new = GetTickCount();
if (mCTime_old != ((mCTime_new + 500) / 1000))
{
//cout << mCTime_old << " " << ((mCTime_new+500)/1000) << endl;
mCTime_old = ((mCTime_new + 500) / 1000);
mCTime_left -= 1000;
bNChange = false;
}
}
cout << " \r" << flush;
if (mCTime_left == 0)
{
bMCycle = false;
}
}
cout << "Mining Cycle " << i1 << " finished" << endl;
system("Pause");
return true;
}
private:
int mlCLen;
float mlMAmt;
};
string sMCycle(mLaser ml, int i1, thread& thread);
int main()
{
vector<mLaser> mlasers;
vector<thread> mthreads;
future<string> futr;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> laser(1, 3);
uniform_int_distribution<> cLRand(30, 90);
uniform_real_distribution<float> mARand(34.0f, 154.3f);
int lasers;
int cycle_time;
float mining_amount;
lasers = laser(gen);
for (int i = 0; i < lasers-1; i++)
{
mlasers.push_back(mLaser(cLRand(gen), mARand(gen)));
mthreads.push_back(thread());
}
for (int i = 0; i < mlasers.size(); i++)
{
futr = async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); });
//mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
}
for (int i = 0; i < mthreads.size(); i++)
{
//mthreads.at(i).join();
}
//string temp = futr.get();
//float out = strtof(temp.c_str(),NULL);
//cout << out << endl;
system("Pause");
return 0;
}
string sMCycle(mLaser ml, int i1, thread& t1)
{
t1 = thread(bind(&mLaser::mCycle, ref(ml), ml.getCLen(), ml.getMAmt()));
//t1.join();
return "122.0";
}
Although writing from multiple threads concurrently to std::cout has to be data race free, there is no guarantee that concurrent writes won't be interleaved. I'm not sure if one write operation of one thread can be interleaved with one write operation from another thread but they can certainly be interleaved between write operations (I think individual outputs from different threads can be interleaved).
What the standard has to say about concurrent access to the standard stream objects (i.e. std::cout, std::cin, etc.) is in 27.4.1 [iostream.objects.overview] paragraph 4:
Concurrent access to a synchronized (27.5.3.4) standard iostream object’s formatted and unformatted input (27.7.2.1) and output (27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (1.10). [ Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. —end note ]
If you want to have output appear in some sort of unit, you will need to synchronize access to std::cout, e.g., by using a mutex.
While Dietmar's answer is sufficient I decided to go a different, much more simple, route. Since I am creating instances of a class and I am accessing those instances in the threads, I chose to update those class' data during the threading and then called the updated data once the thread have finished executing.
This way I do not have to deal with annoying problems like data races nor grabbing output from async in a vector of shared_future. Here is my revised code in case anyone else would like to implement something similar:
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>
using namespace std; //Tacky, but good enough fo a poc D:
class mLaser
{
public:
mLaser(int clen, float mamt, int time_left)
{
mlCLen = clen;
mlMAmt = mamt;
mCTime_left = time_left;
bIsCompleted = false;
}
int getCLen()
{
return mlCLen;
}
float getMAmt()
{
return mlMAmt;
}
void setMCOld(int old)
{
mCTime_old = old;
}
void mCycle()
{
if (!bIsCompleted)
{
int mCTime_new = GetTickCount(); //Get current tick count for comparison to mCOld_time
if (mCTime_old != ((mCTime_new + 500) / 1000)) //Do calculations to see if time has passed since mCTime_old was set
{
//If it has then update mCTime_old and remove one second from mCTime_left.
mCTime_old = ((mCTime_new + 500) / 1000);
mCTime_left -= 1000;
}
cur_time = mCTime_left;
}
else
{
mCTime_left = 0;
}
}
int getCTime()
{
return cur_time;
}
int getCTLeft()
{
return mCTime_left;
}
void mCComp()
{
bIsCompleted = true;
}
bool getCompleted()
{
return bIsCompleted;
}
private:
int mlCLen; //Time of a complete mining cycle
float mlMAmt; //Amoung of ore produced by one mining cycle (not used yet)
int cur_time; //The current time remaining in the current mining cycle; will be removing this as it is just a copy of mCTime_left that I was going to use for another possiblity to make this code work
int mCTime_left; //The current time remaining in the current mining cycle
int mCTime_old; //The last time that mCycle was called
bool bIsCompleted; //Flag to check if a mining cycle has already been accounted for as completed
};
void sMCycle(mLaser& ml, int i1, thread& _thread); //Start a mining cycle thread
//Some global defines
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> laser(1, 10); //A random range for the number of mlaser entities to use
uniform_int_distribution<> cLRand(30, 90); //A random time range in seconds of mining cycle lengths
uniform_real_distribution<float> mARand(34.0f, 154.3f); //A random float range of the amount of ore produced by one mining cycle (not used yet)
int main()
{
//Init some variables for later use
vector<mLaser> mlasers; //Vector to hold mlaser objects
vector<thread> mthreads; //Vector to hold threads
vector<shared_future<int>> futr; //Vector to hold shared_futures (not used yet, might not be used if I can get the code working like this)
int lasers; //Number of lasers to create
int cycle_time; //Mining cycle time
int active_miners = 0; //Number of active mining cycle threads (one for each laser)
float mining_amount; //Amount of ore produced by one mining cycle (not used yet)
lasers = laser(gen); //Get a random number
active_miners = lasers; //Set this to that random number for the while loop later on
//Create the mlaser objects and push them into the mlasers vector
for (int i = 0; i < lasers; i++)
{
int clength = cLRand(gen);
mlasers.push_back(mLaser(clength, mARand(gen), (clength * 1000)));
//Also push thread obects into mthreads for each laser object
mthreads.push_back(thread());
}
//Setup data for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
int mCTime_start = GetTickCount(); //Get cycle start time
mlasers.at(i).setMCOld(((mCTime_start + 500) / 1000));
}
//Print initial display for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds..." << endl;
}
while (active_miners > 0)
{
for (int i = 0; i < mlasers.size(); i++)
{
//futr.push_back(async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }));
async(launch::async, [&mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }); //Launch a thread for the current mlaser object
//mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
}
//Output information from loops
//cout << " \r" << flush; //Return cursor to start of line and flush the buffer for the next info
system("CLS");
for (int i = 0; i < mlasers.size(); i++)
{
if (mlasers.at(i).getCTLeft() != 0) //If mining cycle is not completed
{
cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds..." << endl;
}
else if (mlasers.at(i).getCTLeft() == 0) //If it is completed
{
if (!mlasers.at(i).getCompleted())
{
mlasers.at(i).mCComp();
active_miners -= 1;
}
cout << "Mining Laser " << i + 1 << " has completed its mining cycle!" << endl;
}
}
}
/*for (int i = 0; i < mthreads.size(); i++)
{
mthreads.at(i).join();
}*/
//string temp = futr.get();
//float out = strtof(temp.c_str(),NULL);
//cout << out << endl;
system("Pause");
return 0;
}
void sMCycle(mLaser& ml, int i1,thread& _thread)
{
//Start thread
_thread = thread(bind(&mLaser::mCycle, ref(ml)));
//Join the thread
_thread.join();
}