core_loading_thread.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /*******************************************************************************************
  2. *
  3. * raylib [core] example - loading thread
  4. *
  5. * NOTE: This example requires linking with pthreads library on MinGW,
  6. * it can be accomplished passing -static parameter to compiler
  7. *
  8. * Example originally created with raylib 2.5, last time updated with raylib 3.0
  9. *
  10. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  11. *
  12. * Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
  13. *
  14. ********************************************************************************************/
  15. #include "raylib.h"
  16. #include "pthread.h" // POSIX style threads management
  17. #include <stdatomic.h> // C11 atomic data types
  18. #include <time.h> // Required for: clock()
  19. // Using C11 atomics for synchronization
  20. // NOTE: A plain bool (or any plain data type for that matter) can't be used for inter-thread synchronization
  21. static atomic_bool dataLoaded = false; // Data Loaded completion indicator
  22. static void *LoadDataThread(void *arg); // Loading data thread function declaration
  23. static atomic_int dataProgress = 0; // Data progress accumulator
  24. //------------------------------------------------------------------------------------
  25. // Program main entry point
  26. //------------------------------------------------------------------------------------
  27. int main(void)
  28. {
  29. // Initialization
  30. //--------------------------------------------------------------------------------------
  31. const int screenWidth = 800;
  32. const int screenHeight = 450;
  33. InitWindow(screenWidth, screenHeight, "raylib [core] example - loading thread");
  34. pthread_t threadId; // Loading data thread id
  35. enum { STATE_WAITING, STATE_LOADING, STATE_FINISHED } state = STATE_WAITING;
  36. int framesCounter = 0;
  37. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  38. //--------------------------------------------------------------------------------------
  39. // Main game loop
  40. while (!WindowShouldClose()) // Detect window close button or ESC key
  41. {
  42. // Update
  43. //----------------------------------------------------------------------------------
  44. switch (state)
  45. {
  46. case STATE_WAITING:
  47. {
  48. if (IsKeyPressed(KEY_ENTER))
  49. {
  50. int error = pthread_create(&threadId, NULL, &LoadDataThread, NULL);
  51. if (error != 0) TraceLog(LOG_ERROR, "Error creating loading thread");
  52. else TraceLog(LOG_INFO, "Loading thread initialized successfully");
  53. state = STATE_LOADING;
  54. }
  55. } break;
  56. case STATE_LOADING:
  57. {
  58. framesCounter++;
  59. if (atomic_load_explicit(&dataLoaded, memory_order_relaxed))
  60. {
  61. framesCounter = 0;
  62. int error = pthread_join(threadId, NULL);
  63. if (error != 0) TraceLog(LOG_ERROR, "Error joining loading thread");
  64. else TraceLog(LOG_INFO, "Loading thread terminated successfully");
  65. state = STATE_FINISHED;
  66. }
  67. } break;
  68. case STATE_FINISHED:
  69. {
  70. if (IsKeyPressed(KEY_ENTER))
  71. {
  72. // Reset everything to launch again
  73. atomic_store_explicit(&dataLoaded, false, memory_order_relaxed);
  74. atomic_store_explicit(&dataProgress, 0, memory_order_relaxed);
  75. state = STATE_WAITING;
  76. }
  77. } break;
  78. default: break;
  79. }
  80. //----------------------------------------------------------------------------------
  81. // Draw
  82. //----------------------------------------------------------------------------------
  83. BeginDrawing();
  84. ClearBackground(RAYWHITE);
  85. switch (state)
  86. {
  87. case STATE_WAITING: DrawText("PRESS ENTER to START LOADING DATA", 150, 170, 20, DARKGRAY); break;
  88. case STATE_LOADING:
  89. {
  90. DrawRectangle(150, 200, atomic_load_explicit(&dataProgress, memory_order_relaxed), 60, SKYBLUE);
  91. if ((framesCounter/15)%2) DrawText("LOADING DATA...", 240, 210, 40, DARKBLUE);
  92. } break;
  93. case STATE_FINISHED:
  94. {
  95. DrawRectangle(150, 200, 500, 60, LIME);
  96. DrawText("DATA LOADED!", 250, 210, 40, GREEN);
  97. } break;
  98. default: break;
  99. }
  100. DrawRectangleLines(150, 200, 500, 60, DARKGRAY);
  101. EndDrawing();
  102. //----------------------------------------------------------------------------------
  103. }
  104. // De-Initialization
  105. //--------------------------------------------------------------------------------------
  106. CloseWindow(); // Close window and OpenGL context
  107. //--------------------------------------------------------------------------------------
  108. return 0;
  109. }
  110. // Loading data thread function definition
  111. static void *LoadDataThread(void *arg)
  112. {
  113. int timeCounter = 0; // Time counted in ms
  114. clock_t prevTime = clock(); // Previous time
  115. // We simulate data loading with a time counter for 5 seconds
  116. while (timeCounter < 5000)
  117. {
  118. clock_t currentTime = clock() - prevTime;
  119. timeCounter = currentTime*1000/CLOCKS_PER_SEC;
  120. // We accumulate time over a global variable to be used in
  121. // main thread as a progress bar
  122. atomic_store_explicit(&dataProgress, timeCounter/10, memory_order_relaxed);
  123. }
  124. // When data has finished loading, we set global variable
  125. atomic_store_explicit(&dataLoaded, true, memory_order_relaxed);
  126. return NULL;
  127. }