Skip to content

Commit 3531227

Browse files
committed
Initial commit.
0 parents  commit 3531227

23 files changed

+2196
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build/
2+
*~

LICENSE

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Copyright (c) 2015 Jeff Preshing
2+
3+
This software is provided 'as-is', without any express or implied
4+
warranty. In no event will the authors be held liable for any damages
5+
arising from the use of this software.
6+
7+
Permission is granted to anyone to use this software for any purpose,
8+
including commercial applications, and to alter it and redistribute it
9+
freely, subject to the following restrictions:
10+
11+
1. The origin of this software must not be misrepresented; you must not
12+
claim that you wrote the original software. If you use this software
13+
in a product, an acknowledgement in the product documentation would be
14+
appreciated but is not required.
15+
2. Altered source versions must be plainly marked as such, and must not be
16+
misrepresented as being the original software.
17+
3. This notice may not be removed or altered from any source distribution.

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Various synchronization primitives for multithreaded applications in C++11.
2+
3+
Used in the blog post, "Semaphores are Surprisingly Versatile".
4+
5+
Code is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License). See the `LICENSE` file.
6+
7+
## How to Build the Tests
8+
9+
First, you must generate the projects using [CMake](http://www.cmake.org/). Open a command prompt in the `tests` folder and do the following.
10+
11+
mkdir build
12+
cd build
13+
cmake ..
14+
15+
`cmake` takes an optional `-G` argument to specify which project generator to use. For example, the following command will use the Visual Studio 2012 generator. A complete list of available generators can be found by running `cmake` with no arguments.
16+
17+
cmake -G "Visual Studio 11" ..
18+
19+
On a Unix-like OS, to generate a makefile that builds the release configuration:
20+
21+
cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ..
22+
23+
To generate projects for iOS devices, use the following.
24+
25+
cmake -DCMAKE_TOOLCHAIN_FILE=../../cmake/iOS.cmake -G "Xcode" ..
26+
27+
To build the project, simply use the generated project files as you would normally. On some platforms, you can use CMake to perform the build step, too. For example, on Windows, you can use the command:
28+
29+
cmake --build . --config Release

cmake/BuildSettings.cmake

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Enable debug info in Release.
2+
if(${MSVC})
3+
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi")
4+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi")
5+
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /debug")
6+
elseif(${UNIX})
7+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11 -pthread")
8+
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -g")
9+
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -g")
10+
endif()
11+
12+
if(${IOS})
13+
set(CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos;-iphonesimulator")
14+
set_target_properties(${PROJECT_NAME} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer")
15+
endif()

cmake/iOS.cmake

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
2+
# files which are included with CMake 2.8.4
3+
# It has been altered for iOS development
4+
5+
# Options:
6+
#
7+
# IOS_PLATFORM = OS (default) or SIMULATOR
8+
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
9+
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
10+
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
11+
#
12+
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
13+
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
14+
# If set manually, it will override the default location and force the user of a particular Developer Platform
15+
#
16+
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
17+
# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
18+
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
19+
# If set manually, this will force the use of a specific SDK version
20+
21+
# Macros:
22+
#
23+
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
24+
# A convenience macro for setting xcode specific properties on targets
25+
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
26+
#
27+
# find_host_package (PROGRAM ARGS)
28+
# A macro used to find executable programs on the host system, not within the iOS environment.
29+
# Thanks to the android-cmake project for providing the command
30+
31+
# Standard settings
32+
set (CMAKE_SYSTEM_NAME Darwin)
33+
set (CMAKE_SYSTEM_VERSION 1)
34+
set (UNIX True)
35+
set (APPLE True)
36+
set (IOS True)
37+
38+
# Required as of cmake 2.8.10
39+
set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
40+
41+
# Determine the cmake host system version so we know where to find the iOS SDKs
42+
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
43+
if (CMAKE_UNAME)
44+
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
45+
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
46+
endif (CMAKE_UNAME)
47+
48+
# Force the compilers to gcc for iOS
49+
include (CMakeForceCompiler)
50+
CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple)
51+
CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple)
52+
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
53+
54+
# Skip the platform compiler checks for cross compiling
55+
set (CMAKE_CXX_COMPILER_WORKS TRUE)
56+
set (CMAKE_C_COMPILER_WORKS TRUE)
57+
58+
# All iOS/Darwin specific settings - some may be redundant
59+
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
60+
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
61+
set (CMAKE_SHARED_MODULE_PREFIX "lib")
62+
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
63+
set (CMAKE_MODULE_EXISTS 1)
64+
set (CMAKE_DL_LIBS "")
65+
66+
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
67+
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
68+
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
69+
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
70+
71+
# Hidden visibilty is required for cxx on iOS
72+
set (CMAKE_C_FLAGS_INIT "")
73+
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}")
74+
75+
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
76+
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
77+
78+
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
79+
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
80+
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
81+
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
82+
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
83+
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
84+
85+
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
86+
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
87+
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
88+
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
89+
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
90+
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
91+
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
92+
93+
# Setup iOS platform unless specified manually with IOS_PLATFORM
94+
if (NOT DEFINED IOS_PLATFORM)
95+
set (IOS_PLATFORM "OS")
96+
endif (NOT DEFINED IOS_PLATFORM)
97+
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
98+
99+
# Check the platform selection and setup for developer root
100+
if (${IOS_PLATFORM} STREQUAL "OS")
101+
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
102+
103+
# This causes the installers to properly locate the output libraries
104+
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
105+
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
106+
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
107+
108+
# This causes the installers to properly locate the output libraries
109+
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
110+
else (${IOS_PLATFORM} STREQUAL "OS")
111+
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
112+
endif (${IOS_PLATFORM} STREQUAL "OS")
113+
114+
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
115+
# Note Xcode 4.3 changed the installation location, choose the most recent one available
116+
set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
117+
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
118+
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
119+
if (EXISTS ${XCODE_POST_43_ROOT})
120+
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
121+
elseif(EXISTS ${XCODE_PRE_43_ROOT})
122+
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
123+
endif (EXISTS ${XCODE_POST_43_ROOT})
124+
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
125+
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
126+
127+
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
128+
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
129+
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
130+
if (_CMAKE_IOS_SDKS)
131+
list (SORT _CMAKE_IOS_SDKS)
132+
list (REVERSE _CMAKE_IOS_SDKS)
133+
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
134+
else (_CMAKE_IOS_SDKS)
135+
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
136+
endif (_CMAKE_IOS_SDKS)
137+
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
138+
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
139+
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
140+
141+
# Set the sysroot default to the most recent SDK
142+
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
143+
144+
# set the architecture for iOS
145+
# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually
146+
if (${IOS_PLATFORM} STREQUAL "OS")
147+
set (IOS_ARCH armv6 armv7)
148+
else (${IOS_PLATFORM} STREQUAL "OS")
149+
set (IOS_ARCH i386)
150+
endif (${IOS_PLATFORM} STREQUAL "OS")
151+
152+
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")
153+
154+
# Set the find root to the iOS developer roots and to user defined paths
155+
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root")
156+
157+
# default to searching for frameworks first
158+
set (CMAKE_FIND_FRAMEWORK FIRST)
159+
160+
# set up the default search directories for frameworks
161+
set (CMAKE_SYSTEM_FRAMEWORK_PATH
162+
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
163+
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
164+
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
165+
)
166+
167+
# only search the iOS sdks, not the remainder of the host filesystem
168+
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
169+
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
170+
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
171+
172+
173+
# This little macro lets you set any XCode specific property
174+
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
175+
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
176+
endmacro (set_xcode_property)
177+
178+
179+
# This macro lets you find executable programs on the host system
180+
macro (find_host_package)
181+
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
182+
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
183+
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
184+
set (IOS FALSE)
185+
186+
find_package(${ARGN})
187+
188+
set (IOS TRUE)
189+
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
190+
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
191+
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
192+
endmacro (find_host_package)

common/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
project(Common)
2+
3+
file(GLOB FILES *.h *.cpp)
4+
add_library(Common ${FILES})
5+
include(../cmake/BuildSettings.cmake)

common/autoresetevent.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//---------------------------------------------------------
2+
// For conditions of distribution and use, see
3+
// https://github.com/preshing/cpp11-on-multicore/blob/master/LICENSE
4+
//---------------------------------------------------------
5+
6+
#ifndef __CPP11OM_AUTO_RESET_EVENT_H__
7+
#define __CPP11OM_AUTO_RESET_EVENT_H__
8+
9+
#include <cassert>
10+
#include <thread>
11+
#include "sema.h"
12+
13+
14+
//---------------------------------------------------------
15+
// AutoResetEvent
16+
//---------------------------------------------------------
17+
class AutoResetEvent
18+
{
19+
private:
20+
// m_status == 1: Event object is signaled.
21+
// m_status == 0: Event object is reset and no threads are waiting.
22+
// m_status == -N: Event object is reset and N threads are waiting.
23+
std::atomic<int> m_status;
24+
DefaultSemaphoreType m_sema;
25+
26+
public:
27+
AutoResetEvent(int initialStatus = 0) : m_status(initialStatus)
28+
{
29+
assert(initialStatus >= 0 && initialStatus <= 1);
30+
}
31+
32+
void signal()
33+
{
34+
int oldStatus = m_status.load(std::memory_order_relaxed);
35+
for (;;) // Increment m_status atomically via CAS loop.
36+
{
37+
assert(oldStatus <= 1);
38+
if (oldStatus == 1)
39+
return; // Event object is already signaled.
40+
int newStatus = oldStatus + 1;
41+
if (m_status.compare_exchange_weak(oldStatus, newStatus, std::memory_order_release, std::memory_order_relaxed))
42+
break;
43+
// The compare-exchange failed, likely because another thread changed it between attempts.
44+
// Retry the CAS loop.
45+
}
46+
if (oldStatus < 0)
47+
m_sema.signal(); // Release one waiting thread.
48+
}
49+
50+
void wait()
51+
{
52+
int oldStatus = m_status.fetch_sub(1, std::memory_order_acquire);
53+
assert(oldStatus <= 1);
54+
if (oldStatus < 1)
55+
{
56+
m_sema.wait();
57+
}
58+
}
59+
};
60+
61+
62+
#endif // __CPP11OM_AUTO_RESET_EVENT_H__

common/autoreseteventcondvar.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//---------------------------------------------------------
2+
// For conditions of distribution and use, see
3+
// https://github.com/preshing/modern-cpp-threading/blob/master/LICENSE
4+
//---------------------------------------------------------
5+
6+
#ifndef __MCPPT_AUTO_RESET_EVENT_COND_VAR_H__
7+
#define __MCPPT_AUTO_RESET_EVENT_COND_VAR_H__
8+
9+
#include <cassert>
10+
#include <mutex>
11+
#include <condition_variable>
12+
13+
14+
//---------------------------------------------------------
15+
// AutoResetEventCondVar
16+
//---------------------------------------------------------
17+
class AutoResetEventCondVar
18+
{
19+
private:
20+
// m_status == 1: Event object is signaled.
21+
// m_status == 0: Event object is reset and no threads are waiting.
22+
// m_status == -N: Event object is reset and N threads are waiting.
23+
std::mutex m_mutex;
24+
int m_status;
25+
std::condition_variable m_condition;
26+
27+
public:
28+
AutoResetEventCondVar(int initialStatus = 0) : m_status(initialStatus)
29+
{
30+
assert(initialStatus >= 0 && initialStatus <= 1);
31+
}
32+
33+
void signal()
34+
{
35+
// Increment m_status atomically via critical section.
36+
std::lock_guard<std::mutex> lock(m_mutex);
37+
int oldStatus = m_status;
38+
if (oldStatus == 1)
39+
return; // Event object is already signaled.
40+
m_status++;
41+
if (oldStatus < 0)
42+
m_condition.notify_one(); // Release one waiting thread.
43+
}
44+
45+
void wait()
46+
{
47+
std::unique_lock<std::mutex> lock(m_mutex);
48+
int oldStatus = m_status;
49+
m_status--;
50+
assert(oldStatus <= 1);
51+
if (oldStatus < 1)
52+
{
53+
m_condition.wait(lock);
54+
}
55+
}
56+
};
57+
58+
59+
#endif // __MCPPT_AUTO_RESET_EVENT_COND_VAR_H__

0 commit comments

Comments
 (0)