c++multithreadinganimationconsole-applicationborland-c++

0xC0000005 Error on Multi Thread Animation


So I was making an application using C++ Console, with multi threading as below, then I got an error 0x0000005.

The first time it run it was working as usual. Can anyone help me with this problem?

I am using Code::Blocks IDE with Borland C++ 5.5, and I am planning to make this into Borland C++ 5.02

#include <windows.h>
#include <stdio.h>
#include <dos.h>
#include <iostream.h>
#include <conio.h>

void linesmov(int mseconds, int y);

void linesmov(int mseconds, int y)
{
    int i=0;
    while (true)
    {
        i=i+1;
        // Or system("cls"); If you may...
        gotoxy(i,y);   
        cout << "____||____||____"; 
        gotoxy(i-1,y);
        cout << " ";
        Sleep(mseconds);
        if (i>115)
        {     
            i=0;  
            for(int o = 0; o < 100; o++)
            {
                gotoxy(0,y);   
                cout << "                  ";
            }
        }
    }
}

DWORD WINAPI mythread1(LPVOID lpParameter)
{
    printf("Thread inside %d \n", GetCurrentThreadId());
    linesmov(5,10);
    return 0;
}
DWORD WINAPI mythread2(LPVOID lpParameter)
{
    printf("Thread inside %d \n", GetCurrentThreadId());
    linesmov(30,15);
    return 0;
}

int main(int argc, char* argv[])
{
    HANDLE myhandle1;
    DWORD mythreadid1;
    HANDLE myhandle2;
    DWORD mythreadid2;
    myhandle1 = CreateThread(0,0,mythread1,0,0,&mythreadid1);
    myhandle2 = CreateThread(0,0,mythread2,0,0,&mythreadid2);
    printf("Thread after %d \n", mythreadid1);

    getchar();
    return 0;
}

Solution

  • All of these solutions in comments including mine are definitely not the way how it should be done. The main problem is lack of synchronization between threads and lack of processing their termination. Also, every function should be checked for thread-safe compatibility or should be wrapped to match it.

    Considering std::cout since c++11 we have some data race guarantees:

    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 ]

    So lask of synchronization primitives is oblivious according to this note.

    Considering processing of thread termination.

    HANDLE threadH = CreateThread(...);
    ...
    TerminateThread(threadH, 0); // Terminates a thread.
    WaitForSingleObject(threadH, INFINITE); // Waits until the specified object is in the signaled state or the time-out interval elapses.
    CloseHandle(threadH); // Closes an open object handle.
    

    TerminateThread(), but be aware of this solution, because ..

    WaitForSingleObject()

    And this is only first steps to thread-safe way.

    I would like to recommend C++ Concurrency in Action: Practical Multithreading by Anthony Williams for further reading.

    Rude solution for synchronized output

    #include <Windows.h>
    #include <iostream>
    #include <mutex>
    
    std::mutex _mtx; // global mutex
    
    bool online = true; // or condition_variable
    
    void gotoxy(int x, int y)
    {
        COORD c = { x, y };
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
    }
    
    void linesmov(int mseconds, int y) {
        int i = 0;
        while (online) {
            i = i + 1;
            // Or system("cls"); If you may...
    
            _mtx.lock(); // <- sync here
            gotoxy(i, y);
            std::cout << "____||____||____"; gotoxy(i - 1, y);
            std::cout << " ";
            _mtx.unlock();  
    
            Sleep(mseconds);
            if (i > 75)
            {
                i = 0;
                for (int o = 0; o < 60; o++)
                {
                    _mtx.lock(); // <- sync here
                    gotoxy(0, y);
                    std::cout << "                  ";
                    _mtx.unlock();
                }
            }
        }
    }
    
    DWORD WINAPI mythread1(LPVOID lpParameter)
    {
        std::cout << "Thread 1" << GetCurrentThreadId() << std::endl;
        linesmov(5, 10);
        return 0;
    }
    DWORD WINAPI mythread2(LPVOID lpParameter)
    {
        std::cout << "Thread 2" << GetCurrentThreadId() << std::endl;
        linesmov(30, 15);
        return 0;
    }
    
    int main(int argc, char* argv[])
    {
        DWORD mythreadid1;
        DWORD mythreadid2;
        HANDLE myhandle1 = CreateThread(0, 0, mythread1, 0, 0, &mythreadid1);
        HANDLE myhandle2 = CreateThread(0, 0, mythread2, 0, 0, &mythreadid2);
    
        std::cout << "Base thread: " << GetCurrentThreadId() << std::endl;
    
        getchar();
    
        online = false;
    
        WaitForSingleObject(myhandle1, INFINITE);
        WaitForSingleObject(myhandle2, INFINITE);
    
        CloseHandle(myhandle1);
        CloseHandle(myhandle2);
    
        return 0;
    }