OneLoneCoder / olcPixelGameEngine

The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
Other
3.81k stars 912 forks source link

Multithreading in Visual Studio compiled program #377

Closed PSoftwareOficial closed 1 week ago

PSoftwareOficial commented 1 month ago

Please do not hesitate to call me a moron. Is multithreading allowed? I found no issue which referenced this concept.

If I apply the this code:

#define OLC_PGE_APPLICATION
#include "olcPixelGameEngine.h"
#include <thread>
#include <windows.h>
void PythonURLScript();

class ThreadManager {
public:
    void InitProcess() {
        if (process == 0) {
            process = 1;
            thread_ = std::thread(&PythonURLScript);
        }
    }

    bool isReady() {
        if (process == 2) {
            process = 0;
            return true;
        }
        return false;

    }
    inline void setDone() {
        process = 2;

    }
private:
    std::thread thread_;
    uint8_t process = 0;

};
ThreadManager tMan;

void PythonURLScript() {
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;
    std::cout << "Getting Data" << std::endl;
    //system("Python Visualizador.py");

    // additional information

    // set the size of the structures
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    char file[] = "cmd /c python Visualizador.py";
    HANDLE process;
    // start the program up
    if (CreateProcessA
    (
        NULL,   // the path
        file,                // Command line
        NULL,                   // Process handle not inheritable
        NULL,                   // Thread handle not inheritable
        FALSE,                  // Set handle inheritance to FALSE
        DETACHED_PROCESS,     // Opens file in a separate console
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi           // Pointer to PROCESS_INFORMATION structure
    )) {
        // Wait until child process exits.
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        // Close process and thread handles. 
        tMan.setDone();
    }
    else {
        std::cout << "Could not get data: " << GetLastError() << std::endl;
    }
}

class Game : public olc::PixelGameEngine
{
public:
    Game()
    {
        sAppName = "TestMultiThread";
    }

public:
    bool OnUserCreate() override
    {
        // Called once at the start, so create things here
        return true;
    }

    bool OnUserUpdate(float fElapsedTime) override
    {
        Clear(olc::BLUE);
        if (IsFocused()) {
            if (GetKey(olc::Key::X).bPressed) {
                tMan.InitProcess();
            }

        }
        if (tMan.isReady()) {
            processDone = 1;

        }
        if (processDone) {

            DrawRect({ 0,0 }, { 200,200 }, olc::RED);
        }
        return true;
    }

private:
    uint8_t processDone;
    std::unique_ptr<olc::Sprite> spr;
    std::unique_ptr<olc::Decal> dec;
};

int main()
{
    Game demo;
    if (demo.Construct(500,500, 1, 1))
        demo.Start();

    return 0;
}

The first time I press "X", it works. The second time it crashes and references this code:

olcPixelGameEngine.h line 104

thread& operator=(thread&& _Other) noexcept {
    if (joinable()) {
        _STD terminate(); // per N4950 [thread.thread.assign]/1
    }

    _Thr = _STD exchange(_Other._Thr, {}); //Here Visual Studio shows the exception.
    return *this;
}

If relevant, this is the python script. It just gets some data from google sheets. Used for another project.

import urllib.request
import os

# Replace with the URL of your deployed Google Apps Script
url = "https://script.google.com/macros/s/<google apps script>/exec?GETDATA=0"
filename = "data.csv"

# Download the CSV data
contents = urllib.request.urlopen(url).read().decode()

# Write the data to a file
with open(filename, "wb") as f:
  f.write(contents.encode())
  f.close()
OneLoneCoder commented 1 month ago

Hello! olc::PixelGameEngine has no issue with std::thread usage - I use it myself frequently. Line 104 of PGE is a comment? I'll also add that I dont see any thread.joinable() which is usually a red flag with thread code. It would appear you are assigning a second thread to a thread handle that alreday has a thread associated with it.

PSoftwareOficial commented 1 week ago

Hi, I will have to ask for forgiveness. Apparently, my level of C++ is not good basic foundation skills, but barely not a complete beginner. After a more thorough investigation into multithreading, everything works perfectly.