Finallt got multithreading to kind of work (?)

This commit is contained in:
NaifBanana 2024-04-07 04:18:20 -05:00
parent ae49960048
commit c894f63006
7 changed files with 357 additions and 105 deletions

View File

@ -3,45 +3,87 @@
#define _NB_EVENTS #define _NB_EVENTS
#include <atomic> #include <atomic>
#include <stdexcept>
#include <queue>
#include <array>
#include <memory> #include <memory>
#include <functional> #include <mutex>
#include <string> #include <string>
using state_register = std::atomic<uint64_t>;
namespace NB { namespace NB {
void NULL_FUNC();
class NBEvent { class NBEvent {
friend class NBEventListener; friend class NBEventListener;
public: public:
NBEvent(void (*initFunc)(), uint64_t initMask, const char* initName=""); NBEvent();
NBEvent(const uint64_t, void (*initFunc)() = NULL_FUNC, const char* initName="");
NBEvent(const uint64_t, const char* initName="");
NBEvent(NBEvent&);
NBEvent& operator=(NBEvent& cpy);
~NBEvent();
const std::string getName() const; const std::string getName() const;
const uint64_t getMask() const; const uint64_t getMask() const;
void setMask(const uint64_t); void setMask(const uint64_t);
void setName(const char*); void setName(const char*);
void setFunc(void (*newFunc)()); void setFunc(void (*newFunc)());
const uint64_t check(const uint64_t); virtual const uint64_t check(const uint64_t) const;
private: protected:
uint64_t mask = 0x0;
void (*func)() = nullptr;
std::string name = "";
};
class NBState : public NBEvent {
friend class NBEventListener;
public:
using NBEvent::NBEvent;
const uint64_t check(const uint64_t) const override;
};
enum NBStateChangeType : uint8_t {
STATE_RAISE, STATE_DROP, STATE_SET
};
struct NBStateChange {
uint8_t type;
uint64_t mask; uint64_t mask;
void (*func)();
std::string name;
}; };
class NBEventListener { class NBEventListener {
public: public:
NBEventListener(NBEvent*, uint16_t, std::shared_ptr<std::atomic<uint64_t>> initStatePtr=nullptr, uint64_t initState=0); NBEventListener(NBEvent*, uint16_t, state_register* initStatePtr=nullptr, const uint64_t initState=(uint64_t)0x0);
template<size_t SIZE>
NBEventListener(std::array<NBEvent, SIZE> eventArray, state_register* initStatePtr=nullptr, const uint64_t initState=(uint64_t)0x0)
: NBEventListener(eventArray.data(), eventArray.size(), initStatePtr, initState) {}
NBEvent& operator[](int); NBEvent& operator[](int);
std::shared_ptr<std::atomic<uint64_t>> getStatePtr(); state_register* getStatePtr() const;
const uint64_t getState(); const uint64_t getState() const;
const uint64_t raiseState(const uint64_t); void raiseFlags(const uint64_t);
void raiseFlags(const NBEvent&);
void dropFlags(const uint64_t);
void dropFlags(const NBEvent&);
const bool snoop(const uint64_t) const;
const bool snoop(const NBEvent&) const;
void setState(const uint64_t); void setState(const uint64_t);
void check(); void listen();
void listen(const NBEvent&);
private: protected:
NBEvent* eventList; NBEvent* eventList;
uint16_t numEvents; uint16_t numEvents;
std::shared_ptr<std::atomic<uint64_t>> state; state_register* state;
std::mutex bufferLock;
std::queue<NBStateChange> stateBuffer;
}; };

View File

@ -4,6 +4,7 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <atomic>
#include <array> #include <array>
#include <string> #include <string>
#include <iostream> #include <iostream>
@ -13,6 +14,8 @@ class NBWindow {
public: public:
NBWindow(const std::array<uint16_t, 2>, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL); NBWindow(const std::array<uint16_t, 2>, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL);
NBWindow(const uint16_t, const uint16_t, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL); NBWindow(const uint16_t, const uint16_t, const char*, GLFWmonitor* initMonitor=NULL, GLFWwindow* initWindow=NULL);
~NBWindow();
int init(); int init();
GLFWwindow* getWindow() const; GLFWwindow* getWindow() const;
@ -21,7 +24,9 @@ public:
void resize(const std::array<uint16_t, 2>); void resize(const std::array<uint16_t, 2>);
void resize(const uint16_t x, const uint16_t y); void resize(const uint16_t x, const uint16_t y);
private: protected:
static std::atomic<uint8_t> windowCount;
std::array<uint16_t, 2> windowSize; std::array<uint16_t, 2> windowSize;
std::string windowName; std::string windowName;
bool ready=false, running=false; bool ready=false, running=false;

View File

@ -8,12 +8,32 @@
#include "Window.h" #include "Window.h"
#include "Events.h" #include "Events.h"
void framebuffer_callback(GLFWwindow* window, int width, int height); enum EVENT : uint64_t {
A_PRESSED = (uint64_t)0x1,
B_PRESSED = (uint64_t)0x1 << 1,
CLOSE_WIND_SIG = (uint64_t)0x1 << 2,
CLOSE_PROG_SIG = (uint64_t)0x1 << 3,
void processInputs(GLFWwindow* window); WINDOW_READY_A = (uint64_t)0x1 << 32,
WINDOW_READY_B = (uint64_t)0x1 << 33,
WINDOW_SHOULD_CLOSE = (uint64_t)0x1 << 34,
PROGRAM_SHOULD_CLOSE = (uint64_t)0x1 << 35
};
int renderingProcess(std::atomic<bool>&); void framebuffer_callback(GLFWwindow*, int, int);
int consoleProcess(std::atomic<bool>&); void processInputsA();
void processInputsB();
void windowClosedUser(GLFWwindow*);
void stopWindows();
void waitForWindowClose();
int renderingProcessA();
int renderingProcessB();
#endif #endif

View File

@ -1,12 +1,34 @@
#include "Events.h" #include "Events.h"
namespace NB { namespace NB {
NBEvent::NBEvent(void (*initFunc)(), const uint64_t initMask, const char* initName) { std::invalid_argument null_mask_error("NULL MASK NOT ALLOWED");
mask = initMask;
func = initFunc; void NULL_FUNC() {}
name = initName;
NBEvent::NBEvent() {}
NBEvent::NBEvent(const uint64_t initMask, void (*initFunc)(), const char* initName) : mask{initMask}, func{initFunc}, name{initName} {
if (mask == 0x0) {
throw null_mask_error;
}
} }
NBEvent::NBEvent(const uint64_t initMask, const char* initName) : NBEvent(initMask, NULL_FUNC, initName) {}
NBEvent::NBEvent(NBEvent& cpy) : NBEvent(cpy.mask, cpy.func, cpy.name.c_str()) {}
NBEvent& NBEvent::operator=(NBEvent& cpy) {
func = cpy.func;
name = cpy.name;
mask = cpy.mask;
if (mask==0x0) {
throw null_mask_error;
}
return *this;
}
NBEvent::~NBEvent() {}
const uint64_t NBEvent::getMask() const { const uint64_t NBEvent::getMask() const {
return mask; return mask;
} }
@ -15,33 +37,42 @@ const std::string NBEvent::getName() const {
return name; return name;
} }
void NBEvent::setMask(const uint64_t newMask) {
mask = newMask;
}
void NBEvent::setName(const char* newName) {
name = newName;
}
void NBEvent::setFunc(void (*newFunc)()) { void NBEvent::setFunc(void (*newFunc)()) {
func = newFunc; func = newFunc;
} }
const uint64_t NBEvent::check(const uint64_t state) { void NBEvent::setMask(const uint64_t newMask) {
if (state & mask == mask) { mask = newMask;
func();
}
return state&(~mask);
} }
NBEventListener::NBEventListener(NBEvent* initEventList, uint16_t initNum, std::shared_ptr<std::atomic<uint64_t>> initStatePtr, uint64_t initState) { void NBEvent::setName(const char* newName) {
if (initStatePtr == nullptr) { name = newName;
state = std::shared_ptr<std::atomic<uint64_t>>(new std::atomic<uint64_t>); }
} else {
state = initStatePtr;
}
*state = initState; const uint64_t NBEvent::check(const uint64_t refState) const{
if ((mask!=0) && ((refState&mask)==mask)) {
func();
return refState&(~mask);
}
return refState;
}
const uint64_t NBState::check(const uint64_t refState) const {
if ((mask!=0) && ((refState&mask)==mask)) {
func();
}
return refState;
}
NBEventListener::NBEventListener(NBEvent* initEventList, uint16_t initNum, state_register* initStatePtr, const uint64_t initState)
: stateBuffer() {
if (initStatePtr == nullptr) {
state = new state_register;
}
std::atomic_store<uint64_t>(state, initState);
numEvents = initNum; numEvents = initNum;
eventList = new NBEvent[numEvents];
for (uint16_t i = 0; i < initNum; ++i) { for (uint16_t i = 0; i < initNum; ++i) {
eventList[i] = initEventList[i]; eventList[i] = initEventList[i];
} }
@ -51,31 +82,80 @@ NBEvent& NBEventListener::operator[](int ind) {
return eventList[ind % numEvents]; return eventList[ind % numEvents];
} }
std::shared_ptr<std::atomic<uint64_t>> NBEventListener::getStatePtr() { state_register* NBEventListener::getStatePtr() const {
return std::shared_ptr<std::atomic<uint64_t>>(state); return state;
} }
const uint64_t NBEventListener::getState() { const uint64_t NBEventListener::getState() const {
return *state; return std::atomic_load<uint64_t>(state);
} }
const uint64_t NBEventListener::raiseState(const uint64_t newState) { void NBEventListener::raiseFlags(const uint64_t newState) {
uint64_t oldState = *state; bufferLock.lock();
uint64_t tempState = oldState | newState; stateBuffer.push(NBStateChange{STATE_RAISE, newState});
*state = tempState; bufferLock.unlock();
return tempState; }
void NBEventListener::raiseFlags(const NBEvent& newEvent) {
raiseFlags(newEvent.mask);
}
void NBEventListener::dropFlags(const uint64_t dropState) {
bufferLock.lock();
stateBuffer.push(NBStateChange{STATE_DROP, dropState});
bufferLock.unlock();
}
void NBEventListener::dropFlags(const NBEvent& dropEvent) {
dropFlags(dropEvent.mask);
}
const bool NBEventListener::snoop(const uint64_t refState) const {
return ((getState()&refState)==refState);
}
const bool NBEventListener::snoop(const NBEvent& refEvent) const {
return snoop(refEvent.mask);
} }
void NBEventListener::setState(const uint64_t newState) { void NBEventListener::setState(const uint64_t newState) {
*state = newState; bufferLock.lock();
std::queue<NBStateChange>().swap(stateBuffer);
bufferLock.unlock();
std::atomic_store<uint64_t>(state, newState);
} }
void NBEventListener::check() { void NBEventListener::listen() {
uint64_t oldState = *state; uint64_t oldState = getState();
for (uint16_t i = 0; i < numEvents; ++i) { for (uint16_t i = 0; i < numEvents; ++i) {
oldState = eventList[i].check(oldState); oldState = eventList[i].check(oldState);
} }
*state = oldState; NBStateChange curr;
bufferLock.lock();
for (; !stateBuffer.empty(); stateBuffer.pop()) {
curr = stateBuffer.front();
switch (curr.type) {
case STATE_RAISE:
oldState |= curr.mask;
break;
case STATE_DROP:
oldState &= ~curr.mask;
break;
case STATE_SET:
oldState = curr.mask;
break;
default:
break;
}
}
bufferLock.unlock();
setState(oldState);
}
void NBEventListener::listen(const NBEvent& refEvent) {
uint64_t oldState = getState();
oldState = refEvent.check(oldState);
setState(oldState);
} }
}; };

View File

@ -1,40 +1,57 @@
#include "Window.h" #include "Window.h"
namespace NB { namespace NB {
std::atomic<uint8_t> NBWindow::windowCount = 0;
NBWindow::NBWindow(const uint16_t x, const uint16_t y, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) { NBWindow::NBWindow(const uint16_t x, const uint16_t y, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) {
if (windowCount == 0) {
glfwInit();
}
windowSize = {x, y}; windowSize = {x, y};
windowName = std::string(initName); windowName = std::string(initName);
monitor = initMonitor; monitor = initMonitor;
shareWindow = initWindow; shareWindow = initWindow;
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
ready = true; window = glfwCreateWindow(windowSize[0], windowSize[0], windowName.c_str(), monitor, shareWindow);
if (window == NULL) {
std::cout << "NB::NBWINDOW::COULD NOT CREATE WINDOW(" << windowName << ")\n";
if (windowCount == 0) { glfwTerminate(); }
ready = false;
} else {
windowCount++;
ready = true;
}
} }
NBWindow::NBWindow(const std::array<uint16_t, 2> initSize, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) : NBWindow::NBWindow(const std::array<uint16_t, 2> initSize, const char* initName, GLFWmonitor* initMonitor, GLFWwindow* initWindow) :
NBWindow(initSize[0], initSize[1], initName, initMonitor, initWindow){} NBWindow(initSize[0], initSize[1], initName, initMonitor, initWindow){}
NBWindow::~NBWindow() {
glfwSetWindowShouldClose(window, true);
glfwDestroyWindow(window);
windowCount--;
if (windowCount == 0) {
glfwTerminate();
}
}
int NBWindow::init() { int NBWindow::init() {
if (!ready) { if (!ready) {
std::cout << "NB::NBWINDOW::NOT READY\n"; std::cout << "NB::NBWINDOW::NOT READY\n";
return -1; return -1;
} }
window = glfwCreateWindow(windowSize[0], windowSize[0], windowName.c_str(), monitor, shareWindow);
if (window == NULL) {
std::cout << "NB::NBWINDOW::COULD NOT CREATE WINDOW\n";
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) {
std::cout << "NB::NBWINDOW::COULD NOT INITIALIZE GLAD\n"; std::cout << "NB::NBWINDOW::COULD NOT INITIALIZE GLAD\n";
glfwTerminate(); if (windowCount == 0) { glfwTerminate(); }
return -1; return -1;
} }

View File

@ -1,57 +1,127 @@
#include "funcs.h" #include "funcs.h"
void aPressAlert() {
std::cout << "A PRESSED!\n";
}
void bPressAlert() {
std::cout << "B PRESSED\n";
}
NB::NBEvent aKeyEvent(A_PRESSED, aPressAlert, "A_PRESSED");
NB::NBEvent bKeyEvent(B_PRESSED, bPressAlert, "B_PRESSED");
NB::NBEvent windowCloseEvent(CLOSE_WIND_SIG, stopWindows, "CLOSE_WINDOWS_SIG");
NB::NBState windowAIsReadyState(WINDOW_READY_A, "WINDOW_A_READY");
NB::NBState windowBIsReadyState(WINDOW_READY_B, "WINDOW_B_READY");
NB::NBState windowShouldCloseState(WINDOW_SHOULD_CLOSE, "WINDOW_CLOSING_STATE");
NB::NBState programCloseState(PROGRAM_SHOULD_CLOSE, "PROGRAM_CLOSING_STATE");
std::array<NB::NBEvent, 7> event_list= {
windowCloseEvent,
bKeyEvent,
aKeyEvent,
windowAIsReadyState,
windowBIsReadyState,
windowShouldCloseState,
programCloseState
};
NB::NBEventListener my_listener(event_list);
NB::NBWindow* aWindow;
NB::NBWindow* bWindow;
void framebuffer_callback(GLFWwindow* window, int width, int height) { void framebuffer_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
} }
void processInputs(GLFWwindow* window) { void processInputsA() {
GLFWwindow* window = aWindow->getWindow();
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true); my_listener.raiseFlags(CLOSE_WIND_SIG);
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
my_listener.raiseFlags(A_PRESSED);
} }
} }
int renderingProcess(std::atomic<bool>& shouldStop) { void processInputsB() {
std::cout << "Howdy from rendering!\n"; GLFWwindow* window = bWindow->getWindow();
NB::NBWindow mywindow(800, 600, "Multithreading?"); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
mywindow.init(); my_listener.raiseFlags(CLOSE_WIND_SIG);
GLFWwindow* window = mywindow.getWindow(); }
if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS) {
my_listener.raiseFlags(B_PRESSED);
}
}
glfwSetFramebufferSizeCallback(window, framebuffer_callback); void windowClosedUser(GLFWwindow* windowToClose) {
my_listener.raiseFlags(CLOSE_WIND_SIG);
}
while(!glfwWindowShouldClose(window) && !shouldStop) { void stopWindows() {
processInputs(window); my_listener.raiseFlags(WINDOW_SHOULD_CLOSE);
}
int renderingProcessA() {
std::cout << "Howdy from rendering A!\n";
if ( aWindow->init() ) { return -1; }
my_listener.raiseFlags(WINDOW_READY_A);
glfwSetFramebufferSizeCallback(aWindow->getWindow(), framebuffer_callback);
glfwSetWindowCloseCallback(aWindow->getWindow(), windowClosedUser);
uint64_t count = 0;
while(!my_listener.snoop(WINDOW_SHOULD_CLOSE)) {
glfwMakeContextCurrent(aWindow->getWindow());
processInputsA();
// glClearColor(r/255.0f, g/255.0f, b/255.0f, 1.0f); // glClearColor(r/255.0f, g/255.0f, b/255.0f, 1.0f);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glfwPollEvents(); //glfwPollEvents();
glfwSwapBuffers(window); glfwSwapBuffers(aWindow->getWindow());
count++;
} }
shouldStop = true; my_listener.dropFlags(WINDOW_READY_A);
glfwSetWindowShouldClose(window, true); while(my_listener.snoop(WINDOW_READY_B)) {}
my_listener.raiseFlags(programCloseState);
glfwTerminate();
return 0; return 0;
} }
/* int renderingProcessB() {
int consoleProcess(std::atomic<bool>& shouldStop) { std::cout << "Howdy from rendering B!\n";
char controlInput;
while(!shouldStop) { if ( bWindow->init() ) { return -1; }
std::cin >> controlInput;
switch (controlInput) { my_listener.raiseFlags(WINDOW_READY_B);
case 'r':
r = (r==51)?0:51; glfwSetFramebufferSizeCallback(bWindow->getWindow(), framebuffer_callback);
break; glfwSetWindowCloseCallback(bWindow->getWindow(), windowClosedUser);
case 'g':
g = (g==77)?0:77; uint64_t count = 0;
break;
case 'b': while(!my_listener.snoop(WINDOW_SHOULD_CLOSE)) {
b = (b==77)?0:77; //std::cout << "WINDOW B FRAME\t" << count << "\n";
break; glfwMakeContextCurrent(bWindow->getWindow());
default: processInputsB();
break;
} glClearColor(0.3f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//glfwPollEvents();
glfwSwapBuffers(bWindow->getWindow());
count++;
} }
}*/ my_listener.dropFlags(WINDOW_READY_B);
std::cout << "DONE RENDERING B\n";
while(my_listener.snoop(WINDOW_READY_A)) {}
my_listener.raiseFlags(programCloseState);
return 0;
}

View File

@ -7,17 +7,35 @@
#include "funcs.h" #include "funcs.h"
#include "shader.h" #include "shader.h"
extern NB::NBWindow* aWindow;
extern NB::NBWindow* bWindow;
extern NB::NBEventListener my_listener;
int main() { int main() {
std::cout << "Hello World!\n"; std::cout << "Hello World!\n";
// std::shared_ptr<std::atomic<bool>> shouldClose(new std::atomic<bool>); {
// *shouldClose = false; NB::NBWindow windowa(800, 600, "Multithreading?");
//std::atomic<uint16_t> r=51, g=77, b=77; NB::NBWindow windowb(800, 600, "Multithreading!");
std::atomic<bool> shouldClose= false; aWindow = &windowa;
bWindow = &windowb;
std::thread renderingThread(renderingProcess, std::ref(shouldClose)); glfwMakeContextCurrent(NULL);
std::thread renderingThreadA(renderingProcessA);
std::thread renderingThreadB(renderingProcessB);
renderingThread.join(); renderingThreadB.detach();
renderingThreadA.detach();
while(!my_listener.snoop(PROGRAM_SHOULD_CLOSE)) {
glfwPollEvents();
my_listener.listen();
}
std::cout << "YOUVE REACHED THE END OF THE MAIN THREAD!\n";
}
state_register* state = my_listener.getStatePtr();
delete state;
return 0; return 0;
} }