core_loading_thread.c 6.0 KB

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