High CPU usage while using SFML with multiple threads - c++

I'm using SFML threads, and this makes very high CPU usage.
When only main thread is running, CPU usage is only 1 %, but when 2 threads run, CPU gets as high as 25 %, 3 threads - 50% and so on!!
My CPU has 4 cores, so it seems that each additional thread consumes the whole core!
Why this happens, with 1 thread adding 25% CPU?
It's nothing related to the framerate or sf::sleep(), they make no effect to CPU.
There's a little experimental program which shows everything. When running this code CPU is 25%.
When using addidional threads (commented) then goes as high as 75 %.
#include <iostream>
#include <string>
#include <fstream>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
using namespace std;
sf::RenderWindow window;
sf::Event ev;
bool areEvents=false;
bool Window_Closed=false;
void drawZumthin()
{
for(int i=0; i<4; i++)
{
sf::CircleShape shape(50);
shape.setFillColor(sf::Color::Green);
shape.setPosition(i*100,0);
window.draw(shape);
}
}
void threadOne(int num)
{
long i=0;
while(1)
{
if(i==0) cout<<"Thread no. "<<num<<endl;
//sf::sleep(sf::milliseconds(20));
i++;
}
}
struct Chunk
{
int type;
int tiles[64];
};
void loadNewChunks()
{
cout<<"Loading Chunks\n";
Chunk chunks[25];
for(int i=0; i<25; i++)
{
chunks[i].type=i;
for(int j=0; j<64; j++)
{
chunks[i].tiles[j]=j-i;
}
}
}
void startWind()
{
window.create(sf::VideoMode(400,300),"test");
window.setFramerateLimit(60);
while(window.isOpen())
{
while(window.pollEvent(ev))
{
areEvents=true;
if(ev.type==sf::Event::Closed)
{
window.close();
Window_Closed=true;
}
}
window.clear();
drawZumthin();
window.display();
}
}
void getEvents()
{
cout<<"getEvents started\n";
while(!Window_Closed)
{
if(areEvents)
{
bool newChunk=false;
if(ev.type==sf::Event::TextEntered)
{
if(char(ev.text.unicode)=='w') cout<<"\nUp!\n\n";
if(char(ev.text.unicode)=='s') cout<<"\nDown!\n\n";
if(char(ev.text.unicode)=='a') cout<<"\nLeft!\n\n";
if(char(ev.text.unicode)=='d') cout<<"\nRight!\n\n";
newChunk=true;
}
if(newChunk) loadNewChunks();
areEvents=false;
}
}
cout<<"GetEvents Stopped.\n";
}
int main()
{
/*cout<<"Launching experimental threads\n";
sf::Thread thr2(threadOne, 1);
sf::Thread thr3(threadOne, 2);
thr2.launch();
thr3.launch();*/
cout<<"Launching startWind()\n";
sf::Thread thr1(startWind);
thr1.launch();
sf::sleep(sf::seconds(2));
getEvents();
return 0;
}
Please help me with this issue. Thanks!

Related

Difference in execution time in Windows shell and Git bash shell on windows 7

I have a sample code to optimize
#include <iostream>
#include <vector>
#include <memory>
#include <fstream>
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
template<typename NumType=float>
void RenderSphereOnScreen(const NumType* const _coords)
{
std::cout<<_coords[0]<<" "<<_coords[1]<<" "<<_coords[2]<<std::endl; //assume
}
template<typename NumType>
class SphereRenderTask
{
NumType _coords[3];
public:
SphereRenderTask(const NumType& x, const NumType& y, const NumType& z)
{
if(std::is_same<NumType, int>::value || std::is_same<NumType, float>::value || std::is_same<NumType, double>::value)
{
_coords[0] = x;
_coords[1] = y;
_coords[2] = z;
}
else
{
std::cout << "Error.unknown class type!!\n";
assert(0);
}
}
void operator()() const
{
RenderSphereOnScreen(_coords);
}
};
std::vector<SphereRenderTask<double>*> taskList;
const int THREADS = 3;
void *renderThread(void *index)
{
int tid = *((int *)index);
int max = -1;
int i = tid*(taskList.size()/THREADS);
max = (tid+1)*(taskList.size()/THREADS);
for( std::vector<SphereRenderTask<double>*>::iterator iter=taskList.begin() + i; i<max;)
{
(**iter)();
i++;
iter++;
}
}
void StartRendering(const char* const inputFilePath)
{
void sequential_render();
void multithreaded_render();
taskList.clear(); //init
std::ifstream inputfile(inputFilePath);
double x,y,z;
while (inputfile >> x >> y>> z)
{
taskList.push_back(new SphereRenderTask<double>(x,y,z));
}
int y1 = taskList.size();
inputfile.close();
if(!THREADS)
sequential_render();
else
multithreaded_render();
}
void sequential_render()
{
for(std::vector<SphereRenderTask<double>*>::iterator iter=taskList.begin(); iter!=taskList.end(); ++iter)
{
(**iter)();
}
}
void multithreaded_render()
{
pthread_t tid[THREADS];
for(int i=0;i<THREADS;i++)
{
int tmp = i;
pthread_create(&tid[i], NULL, renderThread, &tmp);
pthread_join(tid[i], NULL);
}
}
int main(int argc, const char* argv[])
{
StartRendering("sphere.txt");
return 0;
}
what this does:
reads a file name "sphere.txt" which contains 100k lines of (x,y,z) which could be float
Example:
136 562 293
629 399 497
682 642 995
739 351 869
607 968 7
262 788 863
....
so on up to 100k lines
save those in a data structure , taskList pointer vector
then display in screen using either sequential_render or multithreaded_render
I have two questions regarding this:
running this gives diff run time on windows shell and git bash shell , both on windows.(compiler mingw g++ 5.1.0)
windows shell:
git bash shell
why does using multithreading doesn't improve running time? I have tried this both on Windows and Linux.
Some small conclusion here:
It just is that way. CMD is horribly slow. This question explains it a bit and provides some links that may be interesting.
You don't actually have multithreading:
pthread_t tid[THREADS]; // Array of threads
for(int i=0;i<THREADS;i++)
{
int tmp = i;
pthread_create(&tid[i], NULL, renderThread, &tmp); // Create one thread
pthread_join(tid[i], NULL); // wait for it to complete
}
So how many threads are working at any given time? Right, only one. So the basic time for printing elements stays the same as in the single-threaded version, but creating and joining a thread takes time that is not required in the single-threaded version. Correct use of multi threading would be:
pthread_t tid[THREADS]; // Array of threads
int tmps[THREADS]; // each thread wants it's own tmp
//start all the threads
for(int i = 0; i < THREADS; i++)
{
tmps[i] = i;
pthread_create(&tid[i], NULL, renderThread, &tmps[i]);
}
// join them all
for(int i = 0; i < THREADS; i++)
{
pthread_join(tid[i], NULL); // wait for it to complete
}
But as I already mentioned in my comment, writing to std::cout from multiple threads will only mix up the lines. Also writing to anything usually requires some synchronisation, so most of the time your threads will just wait. Doesn't seem usefull to use threading here.

c++ - problem with memory in multithreading

I am currently learning about threads in c++ at uni and I have this small project involving ncurses - bouncing balls. I want the balls to spawn untill I press 'x'. After I press the button, it quits but it also shows something about memory protection violation.
When I use gdb, after pressing 'x', it says:
Thread 1 "p" received signal SIGSEGV, Segmentation fault.
0x00007ffff6e6b3c1 in _int_malloc (av=av#entry=0x7ffff71c2c40 ,
bytes=bytes#entry=28) at malloc.c:3612
The problem may be in the for loop but I am not sure.
There is the code I've written:
#include "window.h"
#include <stdlib.h>
#include <time.h>
#include <thread>
#include <unistd.h>
#include <ncurses.h>
#include <atomic>
Window *window;
std::atomic<bool> run(true);
void exit() {
while(run) {
char z = getch();
if(z == 'q') run = false;
}
}
void ballFunction(int a) {
int nr = a;
while (run && window->balls[nr]->counter < 5) {
usleep(50000);
window->balls[nr]->updateBall();
}
window->balls[nr]->x = -1;
window->balls[nr]->y = -1;
}
void updateWindow2() {
while(run) {
usleep(50000);
window->updateWindow();
}
delete window;
}
int main() {
srand(time(NULL));
window = new Window();
int i = 0;
std::vector<std::thread> threads;
std::thread threadWindow(updateWindow2);
std::thread threadExit(exit);
while(run = true) {
window->addBall();
threads.push_back(std::thread(ballFunction, i));
i++;
sleep(1);
}
threadWindow.join();
threadExit.join();
for(int j=2; j<i+2; j++) {
threads[j].join();
}
return 0;
}
#include "window.h"
#include <ncurses.h>
#include <unistd.h>
Window::Window()
{
initWindow();
}
Window::~Window()
{
endwin();
}
void Window::initWindow()
{
initscr();
noecho();
curs_set(FALSE);
clear();
refresh();
}
void Window::addBall()
{
Ball *ball = new Ball(this->ballCounter++);
this->balls.push_back(ball);
}
void Window::updateWindow()
{
for(int i = 0; i<ballCounter; i++)
{
if(balls[i]->update())
{
clear(balls[i]->yy,
balls[i]->xx);
drawBall(balls[i]->y,
balls[i]->x);
}
}
refresh();
}
void Window::clear(int y, int x)
{
mvprintw(y, x, " ");
}
void Window::drawBall(int y, int x)
{
mvprintw(y, x, "o");
}
The problem is that you have one thread adding to the balls vector while other threads are reading from it.
When addBall calls push_back, if the vector capacity is not large enough new memory will be allocated, the existing objects moved or copied to the new block, and the old memory freed. When this happens, the threads running ballFunction can write to memory that is no longer allocated. This results in Undefined Behavior, including the segmentation fault you encounter.
You need to use some form of mutex, or ensure the balls vector has sufficient space allocated (using balls.reserve(more_elements_than_youll_ever_create)).
On an unrelated note, your main while loop will never terminate, because you have an assignment rather than a comparison as the condition (use while (run) or while (run == true)).

How to read std::queue shared with another thread?

My code acquires images and processes them. Performance is critical for my code, so I've tried my hand at multi-threading. Currently, I've only made the acquiring part a separate thread. I'm implementing a simple FIFO buffer using std::queue that stores the acquired images. The acquisition function AcquireImages writes raw image data to this buffer indefinitely until user interruption. Processing function, ProcessImages reads the buffer and processes the image data (currently in the main thread but I'm planning to make this a separate thread as well once I've ironed out issues). Here's my code (modified to form an MCV example):
#include <iostream>
#include <vector>
#include <queue>
#include <atomic>
#include <thread>
#define NUM_CAMERAS 2
void AcquireImages(std::queue<unsigned char*> &rawImageQueue, std::atomic<bool> &quit)
{
unsigned char* rawImage{};
while (!quit)
{
for (int camera = 0; camera < NUM_CAMERAS; camera++)
{
switch (camera)
{
case 0:
rawImage = (unsigned char*)"Cam0Image";
break;
case 1:
rawImage = (unsigned char*)"Cam1Image";
break;
default:
break;
}
rawImageQueue.push(std::move(rawImage));
}
}
}
int ProcessImages(const std::vector<unsigned char*> &rawImageVec, const int count)
{
// Do something to the raw image vector
if (count > 10)
{
return 1;
}
else
{
return 0;
} // In my application, this function only returns non-zero upon user interception.
}
int main()
{
// Preparation
std::vector<unsigned char*> rawImageVec;
rawImageVec.reserve(NUM_CAMERAS);
std::queue<unsigned char*> rawImageQueue;
int count{};
const unsigned int nThreads = 1; // this might grow later
std::atomic<bool> loopFlags[nThreads];
std::thread threads[nThreads];
// Start threads
for (int i = 0; i < nThreads; i++) {
loopFlags[i] = false;
threads[i] = std::thread(AcquireImages, rawImageQueue, ref(loopFlags[i]));
}
// Process images
while (true)
{
// Process the images
for (int cam{}; cam < NUM_CAMERAS; ++cam)
{
rawImageVec.push_back(rawImageQueue.front());
rawImageQueue.pop();
}
int processResult = ProcessImages(move(rawImageVec), count);
if (processResult)
{
std::cout << "Leaving while loop.\n"; // In my application this is triggered by the user
break;
}
rawImageVec.clear();
++count;
}
// Shutdown other threads
for (auto & flag : loopFlags) {
flag = true;
}
// Wait for threads to actually finish.
for (auto& thread : threads) {
thread.join();
}
return 0;
}
Some of you may have already noticed my blunder. What I know is that this program throws an exception atrawImageVec.push_back(rawImageQueue.front());.
The output after throwing the exception reads as follows:
Debug Assertion Failed!
Program: C:\WINDOWS\SYSTEM32\MSVCP140D.dll
File: c:\program files (x86)\microsoft visual studio 14.0\vc\include\deque
Line: 329
Expression: deque iterator not dereferencable
I understand the cause of the issue is probably that I'm reading something that is shared with another thread (Am I correct?). How do I resolve this?
I followed Praetorian's advice in the comments, after checking to see if rawImageQueue is empty, I see that it's always empty. I'm not sure what's causing this.
Here is a generalized example of producer/consumer on a shared queue. The idea is that if you're writing and reading from a data structure, you need some kind of protection around accesses.
For this, the below example uses condition variables and a mutex.
#include <thread>
#include <iostream>
#include <chrono>
#include <queue>
#include <mutex>
#include <vector>
#include <condition_variable>
using namespace std::chrono_literals;
using std::vector;
using std::thread;
using std::unique_lock;
using std::mutex;
using std::condition_variable;
using std::queue;
class WorkQueue
{
condition_variable work_available;
mutex work_mutex;
queue<int> work;
public:
void push_work(int item)
{
unique_lock<mutex> lock(work_mutex);
bool was_empty = work.empty();
work.push(item);
lock.unlock();
if (was_empty)
{
work_available.notify_one();
}
}
int wait_and_pop()
{
unique_lock<mutex> lock(work_mutex);
while (work.empty())
{
work_available.wait(lock);
}
int tmp = work.front();
work.pop();
return tmp;
}
};
int main() {
WorkQueue work_queue;
auto producer = [&]() {
while (true) {
work_queue.push_work(10);
std::this_thread::sleep_for(2ms);
}
};
vector<thread> producers;
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
producers.push_back(std::thread(producer));
std::thread consumer([&]() {
while (true)
{
int work_to_do = work_queue.wait_and_pop();
std::cout << "Got some work: " << work_to_do << std::endl;
}
});
std::for_each(producers.begin(), producers.end(), [](thread &p) {
p.join();
});
consumer.join();
}
Your case is relatively simple as seems you have just one producer and one consumer. Also image processing sounds quite slow (slow enough to not worry about threads contention) and you're switching from single-threaded version so probably no need to bother with highly efficient lock-free implementations.
I'd recommend to study this pseudo code: https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem#Using_monitors, then to learn about condition variables if you need: http://en.cppreference.com/w/cpp/thread/condition_variable.

Parallel merge sort useing _beginthreadex windows API in C++

I'm trying to implement merge sort using win32 _beginthreadex multiple threads in c++. basically it uses _beginthreadex instead of function call to make recursion in each thread. so it will has as many threads as possible. the while loop after the two _beginthreadex call is to check if the children threads finish there job. But when the program access the array a and b, it gives an error that unable to read the memory, I can't find what the problem is. It seems that in the sorting section in children threads the program try to access invalid memory address that info->b goes to the address 0xcccccccc {???}
Thank you
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <process.h>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <sstream>
#include <array>
#include <stdio.h>
using namespace std;
struct ThreadInfo
{
int* a;
int* b;
int low;
int high;
bool run;
};
unsigned __stdcall mergesort(void* x) {
ThreadInfo* info = (ThreadInfo*)x;
if ((info->low) < (info->high))
{
int pivot = ((info->low)+(info->high))/2;
ThreadInfo lowInfo;
ThreadInfo highInfo;
lowInfo.a=info->a;
lowInfo.low=info->low;
lowInfo.high=pivot;
lowInfo.run=true;
highInfo.b=info->b;
highInfo.low=pivot+1;
highInfo.high=info->high;
highInfo.run=true;
//HANDLE myhandlerUp, myhandlerDown;
//creat sub-thread
_beginthreadex(NULL, 0, mergesort, &lowInfo, 0, 0);
//WaitForSingleObject(myhandlerUp,INFINITE);
_beginthreadex(NULL, 0, mergesort, &highInfo, 0, 0);
//WaitForSingleObject(myhandlerDown,INFINITE);
//check if any child threads are working
bool anyRun = true;
while (anyRun)
{
anyRun = false;
anyRun = lowInfo.run || highInfo.run;
}
//doing merge sort
int h,i,j,k,low, high;
low = info->low;
high = info->high;
h=low;
i=low;
j=pivot+1;
while((h<=pivot)&&(j<=high))
{
if(info->a[h]<=info->a[j])
{
info->b[i]=info->a[h];
h++;
}
else
{
info->b[i]=info->a[j];
j++;
}
i++;
}
if(h>pivot)
{
for(k=j; k<=high; k++)
{
info->b[i]=info->a[k];
i++;
}
}
else
{
for(k=h; k<=pivot; k++)
{
info->b[i]=info->a[k];
i++;
}
}
for(k=low; k<=high; k++) info->a[k]=info->b[k];
}
info->run = false;
return 0;
}
void main()
{
ThreadInfo info;
int inputArr[12] = {12,10,43,23,-78,45,123,56,98,41,90,24};
int copiedArr[12]={0,0,0,0,0,0,0,0,0,0,0,0};
info.a=inputArr;
info.b=copiedArr;
for(int i=0; i<12; i++)
cout<<info.a[i]<<" ";
cout<<endl;
info.low=0;
info.high=(11);
info.run=true;
_beginthreadex(NULL, 0, mergesort, &info, 0, 0);
bool finish = info.run;
while(finish){
cout<<"Running...."<<endl;
Sleep(1000);
}
cout<<"After run the result is "<<endl;
for(int i=0; i<12; i++)
cout<<inputArr[i]<<" ";
cout<<endl;
getchar();
}

How to deal with racing threads (C++; TinyThread++)?

Here is a sample of the main code ("Library/stack.h" doesn't really matter, but in any case, it is the last source included in this previous question of mine):
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <tinythread.h>
#include "Library/stack.h"
using namespace std;
using namespace tthread;
#define BOULDERspd 100
// ========================================================================= //
struct Coord {
int x, y;
};
int randOneIn (float n) {
return ((int) (n * (rand() / (RAND_MAX + 1.0))));
}
int randOneIn (int n) {
return ((int) ((float) n * (rand() / (RAND_MAX + 1.0))));
}
// ========================================================================= //
#include <windows.h>
void gotoxy (int column, int line) {
if ((column >= 0) && (line >= 0)) {
COORD coord;
coord.X = column;
coord.Y = line;
SetConsoleCursorPosition(
GetStdHandle( STD_OUTPUT_HANDLE ),
coord
);
}
}
void gotoxy (Coord pos) {
gotoxy(pos.x, pos.y);
}
// ========================================================================= //
void render (char image, Coord pos) {
gotoxy(pos);
cout << image;
}
void unrender (Coord pos) {
gotoxy(pos);
cout << ' ';
}
// ========================================================================= //
char randimage (void) {
return (rand() % 132) + 123;
}
mutex xylock;
class Boulder {
char avatar;
Coord pos;
public:
Boulder (int inix) {
pos.x = inix;
pos.y = 0;
avatar = randimage();
};
void fall (void) {
unrender(pos);
pos.y++;
render(avatar, pos);
Sleep(BOULDERspd);
};
void live (void) {
do {
fall();
} while (y() < 20);
die();
};
void die (void) {
unrender(pos);
pos.y = 0;
};
int x (void) { return pos.x; };
int y (void) { return pos.y; };
};
// ========================================================================= //
class thrStack: public Stack<thread*> {
public:
thrStack (): Stack<thread*> () { };
void pushNrun (thread* elem) {
push(elem);
top->core->joinable();
}
};
void randBoulder (void* arg) {
srand(time(NULL));
Boulder boulder(rand() % 40);
boulder.live();
}
void Boulders (void* arg) {
srand(time(NULL));
thrStack stack;
do {
stack.pushNrun(new thread (randBoulder, 0));
Sleep(rand() % 300);
} while(1);
}
// ========================================================================= //
// ========================================================================= //
int main() {
thread raining (Boulders, 0);
raining.join();
}
I'm new to multi-threading so, to fiddle around with it, I'm trying to make a program that makes random characters constantly fall from the top of the screen, as if it were raining ASCII symbols.
I've noticed, however, a little (big) error in my coding:
bool xylock = false;
class Boulder {
char avatar;
Coord pos;
public:
Boulder (int inix) {
pos.x = inix;
pos.y = 0;
avatar = randimage();
};
void fall (void) {
unrender(pos);
pos.y++;
render(avatar, pos);
Sleep(BOULDERspd);
};
void live (void) {
do {
fall();
} while (y() < 20);
die();
};
void die (void) {
unrender(pos);
pos.y = 0;
};
int x (void) { return pos.x; };
int y (void) { return pos.y; };
};
Because the fall() function uses gotoxy, which changes the 'global cursor', multiple calls to gotoxy would mess up the intended execution of the program. If you try to compile the code as-is, you'd get falling letters that constantly switch position and leave garbage of themselves behind.
Is there any way to use or implement a lock for this and future situations alike with just TinyThread? What is the logic of locks implementing in C++, in general?
EDIT: Modified fall(); is it okay, Caribou?
void fall (void) {
lock_guard<mutex> guard(xylock);
unrender(pos);
pos.y++;
render(avatar, pos);
xylock.unlock();
Sleep(BOULDERspd);
};
You can use the tinythread lib:
http://tinythreadpp.bitsnbites.eu/doc/
Look specifically at lock_guard and mutex
multiple calls to gotoxy would mess up the intended execution of the
program. If you try to compile the code as-is, you'd get falling
letters that constantly switch position and leave garbage of
themselves behind.
create a mutex object to synchronise on, and then in the function you want to be thread safe you create a local lock_guard using it. This mutex can be used in multiple places as well using the lock_guard.
Here I created a very basic threading example without a framework or classes. As you can see, threading and syncronisation isn't C++ work, it's OS work! ;-)
Here I created a simple threadfunction, which I call two times. The threads writing the same variable, but can't do that the same time, so have to protect it. In this sample I use a CRITICAL_SECTION object to lock the variable by one thread. If the one thread lock it, the other can't access it and have to wait until it's free.
Have a closer look and see, I also protected the printf operations. What would happen if you don't do this? You will get a very funny outprint! Find out why and you know how threads and locks work. :-)
#include <windows.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <process.h>
//a global variable (just do do someting):
int g_ThreadCounter = 0;
//global variable to end the threads:
bool g_Run = true;
//do not use global variables, there are better solutions! I just did it here to
//keep it simple and focus on the issue!
//a critical section object - something like a "soft-version" of a mutex to synchronize
//write access on variables
CRITICAL_SECTION critical;
//a thread function
unsigned __stdcall threadFunc(void *pThreadNum)
{
unsigned int iThreadNum = reinterpret_cast<unsigned int>(pThreadNum);
do{
//you need the critical section only when you change values:
EnterCriticalSection(&critical);
g_ThreadCounter++;
printf("from thread: ");
printf("%d", iThreadNum);
printf(" counter = ");
printf("%d", g_ThreadCounter);
printf("\n");
LeaveCriticalSection(&critical);
//sleep a secound
Sleep (1000);
}while(g_Run);
_endthreadex(0);
return 0;
}
int main()
{
unsigned int ThreadID1 = 1;
unsigned int ThreadID2 = 2;
//initialize the critical section with spin count (can be very effective in case
//of short operation times, see msdn for more information)
if(!InitializeCriticalSectionAndSpinCount(&critical, 1000))
{
//DO NOT START THE THREADS, YOU DON'T HAVE SYNCHRONISATION!!!
printf("someting went wrong, press any key to exit");
//do some error handling
getchar();
exit(-1);
}
//start the threads
HANDLE thHandle1 = (HANDLE)_beginthreadex(NULL, 0, &threadFunc, (void*) ThreadID1, 0, NULL);
HANDLE thHandle2 = (HANDLE)_beginthreadex(NULL, 0, &threadFunc, (void*) ThreadID2, 0, NULL);
if(thHandle1 == INVALID_HANDLE_VALUE || thHandle2 == INVALID_HANDLE_VALUE)
{
printf("something went wrong, press any key to exit");
//do some error handling
getchar();
exit(-1);
}
//the main thread sleeps while the other threads are working
Sleep(5000);
//set the stop variable
EnterCriticalSection(&critical);
g_Run = false;
LeaveCriticalSection(&critical);
//wait for the thread; infinite means, you wait as long as the
//thread takes to finish
WaitForSingleObject(thHandle1, INFINITE);
CloseHandle(thHandle1);
WaitForSingleObject(thHandle2, INFINITE);
CloseHandle(thHandle2);
DeleteCriticalSection(&critical);
printf("press any key to exit");
getchar();
return 0;
}
Study the OS on which you are working! It's sometimes better than pay too much attention on Frameworks and foreign classes. This can solve a lot of questions!