test_utils_tls.impl.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. // This is .hpp file included from test_utils.cpp
  5. #ifdef CV_CXX11
  6. #include <thread> // std::thread
  7. #endif
  8. #include "opencv2/core/utils/tls.hpp"
  9. namespace opencv_test { namespace {
  10. class TLSReporter
  11. {
  12. public:
  13. static int g_last_id;
  14. static int g_allocated;
  15. int id;
  16. TLSReporter()
  17. {
  18. id = CV_XADD(&g_last_id, 1);
  19. CV_XADD(&g_allocated, 1);
  20. }
  21. ~TLSReporter()
  22. {
  23. CV_XADD(&g_allocated, -1);
  24. }
  25. };
  26. int TLSReporter::g_last_id = 0;
  27. int TLSReporter::g_allocated = 0;
  28. #ifdef CV_CXX11
  29. template<typename T>
  30. static void callNThreadsWithTLS(int N, TLSData<T>& tls)
  31. {
  32. std::vector<std::thread> threads(N);
  33. for (int i = 0; i < N; i++)
  34. {
  35. threads[i] = std::thread([&]() {
  36. TLSReporter* pData = tls.get();
  37. (void)pData;
  38. });
  39. }
  40. for (int i = 0; i < N; i++)
  41. {
  42. threads[i].join();
  43. }
  44. threads.clear();
  45. }
  46. TEST(Core_TLS, HandleThreadTermination)
  47. {
  48. const int init_id = TLSReporter::g_last_id;
  49. const int init_allocated = TLSReporter::g_allocated;
  50. const int N = 4;
  51. TLSData<TLSReporter> tls;
  52. // use TLS
  53. ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));
  54. EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
  55. EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
  56. }
  57. static void testTLSAccumulator(bool detachFirst)
  58. {
  59. const int init_id = TLSReporter::g_last_id;
  60. const int init_allocated = TLSReporter::g_allocated;
  61. const int N = 4;
  62. TLSDataAccumulator<TLSReporter> tls;
  63. { // empty TLS checks
  64. std::vector<TLSReporter*>& data0 = tls.detachData();
  65. EXPECT_EQ((size_t)0, data0.size());
  66. tls.cleanupDetachedData();
  67. }
  68. // use TLS
  69. ASSERT_NO_THROW(callNThreadsWithTLS(N, tls));
  70. EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
  71. EXPECT_EQ(init_allocated + N, TLSReporter::g_allocated);
  72. if (detachFirst)
  73. {
  74. std::vector<TLSReporter*>& data1 = tls.detachData();
  75. EXPECT_EQ((size_t)N, data1.size());
  76. // no data through gather after detachData()
  77. std::vector<TLSReporter*> data2;
  78. tls.gather(data2);
  79. EXPECT_EQ((size_t)0, data2.size());
  80. tls.cleanupDetachedData();
  81. EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
  82. EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
  83. EXPECT_EQ((size_t)0, data1.size());
  84. }
  85. else
  86. {
  87. std::vector<TLSReporter*> data2;
  88. tls.gather(data2);
  89. EXPECT_EQ((size_t)N, data2.size());
  90. std::vector<TLSReporter*>& data1 = tls.detachData();
  91. EXPECT_EQ((size_t)N, data1.size());
  92. tls.cleanupDetachedData();
  93. EXPECT_EQ((size_t)0, data1.size());
  94. // data2 is not empty, but it has invalid contents
  95. EXPECT_EQ((size_t)N, data2.size());
  96. }
  97. EXPECT_EQ(init_id + N, TLSReporter::g_last_id);
  98. EXPECT_EQ(init_allocated + 0, TLSReporter::g_allocated);
  99. }
  100. TEST(Core_TLS, AccumulatorHoldData_detachData) { testTLSAccumulator(true); }
  101. TEST(Core_TLS, AccumulatorHoldData_gather) { testTLSAccumulator(false); }
  102. #endif
  103. }} // namespace