I'm making a small little project that shows step by step how different sorting algorithms work. Essentially just a bunch of random lines drawn with opengl that then get sorted. In order to show it step my step, after each swap in the algorithm I redraw the screen and have the program sleep for about 5 milliseconds. When run inside Visual Studio with the debugger there are no problems at all, but if I run without the debugger, either with ctrl+f5
or from the windows explorer the display will freeze up and stop drawing about half way through the sorting algorithm (regardless of what algorithm) -- However, the console will still output the info (number of comparisons and swaps) at the end, and based on how long it takes, the delay does indeed to still be in effect). I've narrowed this down to be because of sleep function, as when I don't use a sleep it works flawlessly, just too fast. To make things even more strange, I sent the exe to a friend and it worked with no problems for him. I've also tried setting _NO_DEBUG_HEAP
to 1 to see if I could catch the error with the debugger attached, but no luck there.
On the chance that something is just weird with Windows.h Sleep(x)
I created my own little function using the ctime clock
type/function, but still this weird no debugger error continues.
My own sleep function:
void slp(clock_t wait)
{
clock_t goal;
goal = wait + clock();
while(goal > clock());
}
Is there anything that might explain why this will work for one person (my friend) but not myself? Some more code is included below, though I don't believe any of it is an issue, I think its just that I need a better way of sleeping/delaying the program.
/*My window creation/drawing code, just in case its a glut issue some how
(normally I'd use glfw but couldn't get things like glRecti to work for the life of me)*/
constexpr int N = 320;
int heights[ N ];
void gfx();
int main(int argc, char** argv)
{
for (int i = 0; i < N; i++)
{
heights[ i ] = rand() % 600;
}
glutInit(&argc, argv);
glutInitWindowSize(1280, 720);
int cx = (glutGet(GLUT_SCREEN_WIDTH) - 1280) / 2;
int cy = (glutGet(GLUT_SCREEN_HEIGHT) - 720) / 2;
glutInitWindowPosition(cx, cy);
glutCreateWindow("Sorting Visualizer");
glutDisplayFunc(gfx);
glClearColor(0, 0, 0, 1);
gluOrtho2D(0, 1280, 0, 720);
glutMainLoop();
return 0;
}
The gfx function is simply
void gfx()
{
glClear(GL_COLOR_BUFFER_BIT);
HeapSorter<int, N> heap(heights);
heap.sort();
heap.printInfo();
}
And now the sorting algorithm:
template <typename T, int N>
class HeapSorter : public Sorter<T, N>
{
using Sorter<T, N>::drawStep;
using Sorter<T, N>::mSwaps;
using Sorter<T, N>::mCompares;
using Sorter<T, N>::mArr;
using Sorter<T, N>::mName;
public:
HeapSorter(T arr[ N ], int slp = 5) : Sorter<T, N>("Heap Sort", arr, slp) {}
void sort()
{
for (int i = N / 2 - 1; i >= 0; i--)
{
heapify(N, i);
}
for (int i = N - 1; i > 0; i--)
{
std::swap(mArr[ 0 ], mArr[ i ]);
mSwaps++;
drawStep();
heapify(i, 0);
}
}
private:
void heapify(const int n, int i)
{
int largest = i;
int left = 2 * i + 1;
int right = 2 * i + 2;
++mCompares;
if (left < n && mArr[ left ] > mArr[ largest ])
{
largest = left;
}
++mCompares;
if (right < n && mArr[ right ] > mArr[ largest ])
{
largest = right;
}
if (largest != i)
{
std::swap(mArr[ i ], mArr[ largest ]);
++mSwaps;
drawStep();
heapify(n, largest);
}
}
};
The super class just handles drawing, the sleep function occurs in drawStep
template <typename T, int N>
class Sorter
{
public:
Sorter(std::string name, T arr[ N ], const int slp = 5) :
mName(std::move(name)),
mSleep(slp)
{
for (auto i = 0; i < N; i++)
{
mArr[ i ] = arr[ i ];
}
}
void printInfo() const
{
std::cout << mName << " - Compares: " << mCompares << " - Swaps: " << mSwaps << "\n";
}
protected:
static void drawText(const float x, const float y, const std::string& txt)
{
glColor3f(1, 1, 1);
glRasterPos2f(x, y);
for (auto i : txt)
{
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, i);
}
}
void drawStep()
{
glClear(GL_COLOR_BUFFER_BIT);
drawText(5, 700, mName);
drawText(5, 680, "Compares: " + std::to_string(mCompares));
drawText(5, 660, "Swaps: " + std::to_string(mSwaps));
drawText(5, 640, "Sleep: " + std::to_string(mSleep) + " ms");
glColor3f(1.f, 0.f, 0.f);
for (auto i = 0; i < N; i++)
{
glRecti(4 * i, 100, 4 * i + 3, 100 + mArr[ i ]);
}
glFlush();
SLP(mSleep);
}
std::string mName;
int mSleep;
int mCompares = 0;
int mSwaps = 0;
T mArr[ N ];
};
SLP
is simply a macro so I could quickly test different sleep functions without having to change any place I might have used it