Skip to content

Instantly share code, notes, and snippets.

@bwedding
Last active December 14, 2023 08:59
Show Gist options
  • Save bwedding/3f67ce5c19feb70aacc45aa3b1111deb to your computer and use it in GitHub Desktop.
Save bwedding/3f67ce5c19feb70aacc45aa3b1111deb to your computer and use it in GitHub Desktop.
Example of C++ std::thread Windows Specific. Creates 30 threads which draw red, white and blue bar graphs moving at separate rates.
#include <iostream>
#include <thread>
#include <mutex>
#include <random>
#include <Windows.h>
using namespace std::chrono_literals;
constexpr int LINE_LEN = 100;
bool Running = false;
std::mutex ConsoleLock;
void SetConsoleColor(WORD color)
{
const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, color);
}
void GotoXY(const short x, const short y)
{
const COORD pos = { x, y };
const HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output, pos);
}
void ClearScreen()
{
const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hConsole, &csbi);
const DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
const COORD homeCoords = { 0, 0 };
DWORD count;
FillConsoleOutputCharacter(hConsole, (TCHAR)' ', cellCount, homeCoords, &count);
FillConsoleOutputAttribute(hConsole, csbi.wAttributes, cellCount, homeCoords, &count);
SetConsoleCursorPosition(hConsole, homeCoords);
}
std::string MakeBar(const int value)
{
return std::string(value, static_cast<char>(219));
}
void ClearCurrentLine()
{
std::cout << '\r' << "\x1B[K";
}
void DrawGraph(const short line, const int i, const bool down)
{
std::lock_guard guard(ConsoleLock);
if (down)
{
GotoXY(1, line);
ClearCurrentLine();
}
if (line % 3 == 0)
SetConsoleColor(FOREGROUND_RED | FOREGROUND_INTENSITY); // Red
else if (line % 3 == 1)
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); // White
else
SetConsoleColor(FOREGROUND_BLUE | FOREGROUND_INTENSITY); // Blue
GotoXY(1, line);
std::cout << MakeBar(i);
}
void DrawBar(const short line, const int speed)
{
// Wait for the green flag so we all start at the same time
while (!Running)
std::this_thread::sleep_for(std::chrono::milliseconds(speed));
while (Running)
{
for (int i = 1; i < LINE_LEN; i++)
{
DrawGraph(line, i, false);
std::this_thread::sleep_for(std::chrono::microseconds(speed));
}
for (int i = LINE_LEN - 1; i > 0; i--)
{
DrawGraph(line, i, true);
std::this_thread::sleep_for(std::chrono::microseconds(speed));
}
}
}
void hideCursor()
{
const HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO info;
info.dwSize = 100;
info.bVisible = FALSE;
SetConsoleCursorInfo(consoleHandle, &info);
}
int main()
{
hideCursor();
SetConsoleOutputCP(437); // To make console display extended ASCII
std::random_device rd;
std::mt19937 eng(rd());
std::uniform_int_distribution<> distr(80, 40000);
std::ios_base::sync_with_stdio(false);
setvbuf(stdout, nullptr, _IONBF, 0);
constexpr int NUM_THREADS = 30;
std::vector<std::jthread> threads;
threads.reserve(NUM_THREADS);
for (int i = 1; i <= NUM_THREADS; ++i)
threads.emplace_back(DrawBar, i, distr(eng));
Running = true;
// Let them run for a while
std::this_thread::sleep_for(8s);
// Tell them to stop
Running = false;
// Wait until they're all finished before we clear screen
for (auto& thread : threads)
if (thread.joinable())
thread.join();
ClearScreen();
// Reset to default color (usually white)
SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment