| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 | // Ceres Solver - A fast non-linear least squares minimizer// Copyright 2018 Google Inc. All rights reserved.// http://ceres-solver.org///// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are met://// * Redistributions of source code must retain the above copyright notice,//   this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above copyright notice,//   this list of conditions and the following disclaimer in the documentation//   and/or other materials provided with the distribution.// * Neither the name of Google Inc. nor the names of its contributors may be//   used to endorse or promote products derived from this software without//   specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE// POSSIBILITY OF SUCH DAMAGE.//// Author: vitus@google.com (Michael Vitus)// This include must come before any #ifndef check on Ceres compile options.#include "ceres/internal/port.h"#ifdef CERES_USE_CXX_THREADS#include <chrono>#include <thread>#include "ceres/concurrent_queue.h"#include "gmock/gmock.h"#include "gtest/gtest.h"namespace ceres {namespace internal {// A basic test of push and pop.TEST(ConcurrentQueue, PushPop) {  ConcurrentQueue<int> queue;  const int num_to_add = 10;  for (int i = 0; i < num_to_add; ++i) {    queue.Push(i);  }  for (int i = 0; i < num_to_add; ++i) {    int value;    ASSERT_TRUE(queue.Pop(&value));    EXPECT_EQ(i, value);  }}// Push and pop elements from the queue after StopWaiters has been called.TEST(ConcurrentQueue, PushPopAfterStopWaiters) {  ConcurrentQueue<int> queue;  const int num_to_add = 10;  int value;  // Pop should return immediately with false with an empty queue.  ASSERT_FALSE(queue.Pop(&value));  for (int i = 0; i < num_to_add; ++i) {    queue.Push(i);  }  // Call stop waiters to ensure we can still Push and Pop from the queue.  queue.StopWaiters();  for (int i = 0; i < num_to_add; ++i) {    ASSERT_TRUE(queue.Pop(&value));    EXPECT_EQ(i, value);  }  // Pop should return immediately with false with an empty queue.  ASSERT_FALSE(queue.Pop(&value));  // Ensure we can still push onto the queue after StopWaiters has been called.  const int offset = 123;  for (int i = 0; i < num_to_add; ++i) {    queue.Push(i + offset);  }  for (int i = 0; i < num_to_add; ++i) {    int value;    ASSERT_TRUE(queue.Pop(&value));    EXPECT_EQ(i + offset, value);  }  // Pop should return immediately with false with an empty queue.  ASSERT_FALSE(queue.Pop(&value));  // Try calling StopWaiters again to ensure nothing changes.  queue.StopWaiters();  queue.Push(13456);  ASSERT_TRUE(queue.Pop(&value));  EXPECT_EQ(13456, value);}// Push and pop elements after StopWaiters and EnableWaiters has been called.TEST(ConcurrentQueue, PushPopStopAndStart) {  ConcurrentQueue<int> queue;  int value;  queue.Push(13456);  queue.Push(256);  queue.StopWaiters();  ASSERT_TRUE(queue.Pop(&value));  EXPECT_EQ(13456, value);  queue.EnableWaiters();  // Try adding another entry after enable has been called.  queue.Push(989);  // Ensure we can pop both elements off.  ASSERT_TRUE(queue.Pop(&value));  EXPECT_EQ(256, value);  ASSERT_TRUE(queue.Pop(&value));  EXPECT_EQ(989, value);  // Re-enable waiting.  queue.EnableWaiters();  // Pop should return immediately with false with an empty queue.  ASSERT_FALSE(queue.Pop(&value));}// A basic test for Wait.TEST(ConcurrentQueue, Wait) {  ConcurrentQueue<int> queue;  int value;  queue.Push(13456);  ASSERT_TRUE(queue.Wait(&value));  EXPECT_EQ(13456, value);  queue.StopWaiters();  // Ensure waiting returns immediately after StopWaiters.  EXPECT_FALSE(queue.Wait(&value));  EXPECT_FALSE(queue.Wait(&value));  EXPECT_FALSE(queue.Pop(&value));  // Calling StopWaiters multiple times does not change anything.  queue.StopWaiters();  EXPECT_FALSE(queue.Wait(&value));  EXPECT_FALSE(queue.Wait(&value));  queue.Push(989);  queue.Push(789);  ASSERT_TRUE(queue.Wait(&value));  EXPECT_EQ(989, value);  ASSERT_TRUE(queue.Wait(&value));  EXPECT_EQ(789, value);}// Ensure wait blocks until an element is pushed. Also ensure wait does not// block after StopWaiters is called and there is no value in the queue.// Finally, ensures EnableWaiters re-enables waiting.TEST(ConcurrentQueue, EnsureWaitBlocks) {  ConcurrentQueue<int> queue;  int value = 0;  bool valid_value = false;  bool waiting = false;  std::mutex mutex;  std::thread thread([&]() {    {      std::lock_guard<std::mutex> lock(mutex);      waiting = true;    }    int element = 87987;    bool valid = queue.Wait(&element);    {      std::lock_guard<std::mutex> lock(mutex);      waiting = false;      value = element;      valid_value = valid;    }  });  // Give the thread time to start and wait.  std::this_thread::sleep_for(std::chrono::milliseconds(500));  // Ensure nothing is has been popped off the queue  {    std::lock_guard<std::mutex> lock(mutex);    EXPECT_TRUE(waiting);    ASSERT_FALSE(valid_value);    ASSERT_EQ(0, value);  }  queue.Push(13456);  // Wait for the thread to pop the value.  thread.join();  EXPECT_TRUE(valid_value);  EXPECT_EQ(13456, value);}TEST(ConcurrentQueue, StopAndEnableWaiters) {  ConcurrentQueue<int> queue;  int value = 0;  bool valid_value = false;  bool waiting = false;  std::mutex mutex;  auto task = [&]() {    {      std::lock_guard<std::mutex> lock(mutex);      waiting = true;    }    int element = 87987;    bool valid = queue.Wait(&element);    {      std::lock_guard<std::mutex> lock(mutex);      waiting = false;      value = element;      valid_value = valid;    }  };  std::thread thread_1(task);  // Give the thread time to start and wait.  std::this_thread::sleep_for(std::chrono::milliseconds(500));  // Ensure the thread is waiting.  {    std::lock_guard<std::mutex> lock(mutex);    EXPECT_TRUE(waiting);  }  // Unblock the thread.  queue.StopWaiters();  thread_1.join();  // Ensure nothing has been popped off the queue.  EXPECT_FALSE(valid_value);  EXPECT_EQ(87987, value);  // Ensure another call to Wait returns immediately.  EXPECT_FALSE(queue.Wait(&value));  queue.EnableWaiters();  value = 0;  valid_value = false;  waiting = false;  // Start another task waiting for an element to be pushed.  std::thread thread_2(task);  // Give the thread time to start and wait.  std::this_thread::sleep_for(std::chrono::milliseconds(500));  // Ensure nothing is popped off the queue.  {    std::lock_guard<std::mutex> lock(mutex);    EXPECT_TRUE(waiting);    ASSERT_FALSE(valid_value);    ASSERT_EQ(0, value);  }  queue.Push(13456);  // Wait for the thread to pop the value.  thread_2.join();  EXPECT_TRUE(valid_value);  EXPECT_EQ(13456, value);}}  // namespace internal}  // namespace ceres#endif // CERES_USE_CXX_THREADS
 |