concurrent and unit tests, concurrently linked list test (not production ready linked list :))
This commit is contained in:
parent
894ef67bc0
commit
c79706c249
@ -13,13 +13,25 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
|
||||
|
||||
# functions
|
||||
|
||||
# prints all included directories
|
||||
function(list_includes)
|
||||
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
|
||||
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
PROPERTY INCLUDE_DIRECTORIES)
|
||||
foreach(dir ${dirs})
|
||||
message(STATUS "dir='${dir}'")
|
||||
endforeach()
|
||||
endfunction(list_includes)
|
||||
|
||||
# get file names from list of file paths
|
||||
function(get_file_names file_paths file_names)
|
||||
set(file_names "")
|
||||
foreach(file_path ${file_paths})
|
||||
get_filename_component (file_name ${file_path} NAME_WE)
|
||||
list(APPEND file_names ${file_name})
|
||||
endforeach()
|
||||
set(file_names "${file_names}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# custom targets
|
||||
|
||||
# move test data data to the build directory
|
||||
|
@ -28,5 +28,8 @@ make
|
||||
ctest
|
||||
ctest -V
|
||||
ctest -R test_name
|
||||
ctest -R unit
|
||||
ctest -R concurrent
|
||||
ctest -R concurrent --parallel 4
|
||||
```
|
||||
|
||||
|
46
src/data_structures/linked_list.hpp
Normal file
46
src/data_structures/linked_list.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "threading/sync/lockable.hpp"
|
||||
#include "threading/sync/spinlock.hpp"
|
||||
|
||||
template <typename value_type, typename lock_type = SpinLock>
|
||||
class LinkedList : public Lockable<lock_type>
|
||||
{
|
||||
public:
|
||||
std::size_t size() const
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
return data.size();
|
||||
}
|
||||
|
||||
void push_front(const value_type &value)
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
data.push_front(value);
|
||||
}
|
||||
|
||||
void push_front(value_type &&value)
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
data.push_front(std::forward<value_type>(value));
|
||||
}
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
data.pop_front();
|
||||
}
|
||||
|
||||
// value_type& as return value
|
||||
// would not be concurrent
|
||||
value_type front()
|
||||
{
|
||||
auto guard = this->acquire_unique();
|
||||
return data.front();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<value_type> data;
|
||||
};
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "sync/spinlock.hpp"
|
||||
#include "sync/lockable.hpp"
|
||||
|
||||
template <class T>
|
||||
class SpinLockedList : Lockable<SpinLock>
|
||||
{
|
||||
public:
|
||||
|
||||
void push_front(T item)
|
||||
{
|
||||
auto guard = this->acquire();
|
||||
head = new Node(item, head);
|
||||
}
|
||||
|
||||
bool remove(const T&)
|
||||
{
|
||||
// HM!
|
||||
}
|
||||
|
||||
private:
|
||||
struct Node : Lockable<SpinLock>
|
||||
{
|
||||
Node(T item, Node* next) : item(item), next(next) {}
|
||||
|
||||
T item;
|
||||
Node* next;
|
||||
};
|
||||
|
||||
Node* head;
|
||||
|
||||
// TODO add removed items to a list for garbage collection
|
||||
// std::list<Node*> removed;
|
||||
};
|
@ -21,25 +21,44 @@ set(catch_source_dir ${source_dir})
|
||||
|
||||
include_directories(${catch_source_dir}/include)
|
||||
|
||||
# find tests
|
||||
file(GLOB_RECURSE test_files ${CMAKE_HOME_DIRECTORY}/tests/*.cpp)
|
||||
set(tests "")
|
||||
foreach(test_file ${test_files})
|
||||
get_filename_component(test_name ${test_file} NAME_WE)
|
||||
list(APPEND tests ${test_name})
|
||||
endforeach()
|
||||
MESSAGE(STATUS "Available tests are: ${tests}")
|
||||
## UNIT TESTS
|
||||
|
||||
# copy test data
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/tests/data DESTINATION ${CMAKE_BINARY_DIR}/tests)
|
||||
# find unit tests
|
||||
file(GLOB_RECURSE unit_test_files ${CMAKE_HOME_DIRECTORY}/tests/unit/*.cpp)
|
||||
get_file_names("${unit_test_files}" file_names)
|
||||
set(unit_test_names "${file_names}")
|
||||
message(STATUS "Available unit tests are: ${unit_test_names}")
|
||||
|
||||
# build tests
|
||||
foreach(test ${tests})
|
||||
add_executable(${test} ${test}.cpp)
|
||||
# copy unit test data
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/tests/data
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/tests)
|
||||
|
||||
# build unit tests
|
||||
foreach(test ${unit_test_names})
|
||||
set(test_name unit_${test})
|
||||
add_executable(${test_name} unit/${test}.cpp)
|
||||
# TODO: separate dependencies
|
||||
target_link_libraries(${test} stdc++fs)
|
||||
target_link_libraries(${test} cypher_lib)
|
||||
target_link_libraries(${test} Threads::Threads)
|
||||
add_test(NAME ${test} COMMAND ${test})
|
||||
set_property(TARGET ${test} PROPERTY CXX_STANDARD 14)
|
||||
target_link_libraries(${test_name} stdc++fs)
|
||||
target_link_libraries(${test_name} cypher_lib)
|
||||
target_link_libraries(${test_name} Threads::Threads)
|
||||
add_test(NAME ${test_name} COMMAND ${test_name})
|
||||
set_property(TARGET ${test_name} PROPERTY CXX_STANDARD 14)
|
||||
endforeach()
|
||||
|
||||
## CONCURRENCY TESTS
|
||||
|
||||
# find concurrency tests
|
||||
file(GLOB_RECURSE concurrency_test_files
|
||||
${CMAKE_HOME_DIRECTORY}/tests/concurrent/*.cpp)
|
||||
get_file_names("${concurrency_test_files}" file_names)
|
||||
set(concurrency_test_names "${file_names}")
|
||||
message(STATUS "Available concurrency tests are: ${concurrency_test_names}")
|
||||
|
||||
# build concurrency tests
|
||||
foreach(test ${concurrency_test_names})
|
||||
set(test_name concurrent_${test})
|
||||
add_executable(${test_name} concurrent/${test}.cpp)
|
||||
target_link_libraries(${test_name} Threads::Threads)
|
||||
add_test(NAME ${test_name} COMMAND ${test_name})
|
||||
set_property(TARGET ${test_name} PROPERTY CXX_STANDARD 14)
|
||||
endforeach()
|
||||
|
60
tests/concurrent/linked_list.cpp
Normal file
60
tests/concurrent/linked_list.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "data_structures/linked_list.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
template <typename list_type>
|
||||
void test_concurrent_list_access(list_type &list, std::size_t size)
|
||||
{
|
||||
// test concurrent access
|
||||
for (int i = 0; i < 1000000; ++i) {
|
||||
|
||||
std::thread t1([&list] {
|
||||
list.push_front(1);
|
||||
list.pop_front();
|
||||
});
|
||||
|
||||
std::thread t2([&list] {
|
||||
list.push_front(2);
|
||||
list.pop_front();
|
||||
});
|
||||
|
||||
t1.join();
|
||||
t2.join();
|
||||
|
||||
assert(list.size() == size);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
LinkedList<int> list;
|
||||
|
||||
// push & pop operations
|
||||
list.push_front(10);
|
||||
list.push_front(20);
|
||||
auto a = list.front();
|
||||
assert(a == 20);
|
||||
list.pop_front();
|
||||
a = list.front();
|
||||
assert(a == 10);
|
||||
list.pop_front();
|
||||
assert(list.size() == 0);
|
||||
|
||||
// concurrent test
|
||||
LinkedList<int> concurrent_list;
|
||||
concurrent_list.push_front(1);
|
||||
concurrent_list.push_front(1);
|
||||
std::list<int> no_concurrent_list;
|
||||
no_concurrent_list.push_front(1);
|
||||
no_concurrent_list.push_front(1);
|
||||
|
||||
test_concurrent_list_access(concurrent_list, 2);
|
||||
// test_concurrent_list_access(no_concurrent_list, 2);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user