Run clang-format

This commit is contained in:
Bassem Girgis
2018-10-18 00:40:34 -05:00
parent fffe4528da
commit 31c32e368a
149 changed files with 5974 additions and 6287 deletions

104
.clang-format Normal file
View File

@@ -0,0 +1,104 @@
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces : Custom
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeCategories:
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: false
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 2
UseTab: Never

114
.cproject Normal file
View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012" name="Debug" parent="cdt.managedbuild.config.gnu.cross.exe.debug">
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.debug.1122035376" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.debug">
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.890879207" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
<builder buildPath="${workspace_loc:/concurrency-in-action}/Debug" id="cdt.managedbuild.builder.gnu.cross.730695170" managedBuildOn="true" name="Gnu Make Builder.Debug" superClass="cdt.managedbuild.builder.gnu.cross"/>
<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.680385655" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.option.optimization.level.1148144853" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
<option defaultValue="gnu.c.debugging.level.max" id="gnu.c.compiler.option.debugging.level.1348513497" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.2123668139" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.241274475" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
<option id="gnu.cpp.compiler.option.optimization.level.427163038" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
<option defaultValue="gnu.cpp.compiler.debugging.level.max" id="gnu.cpp.compiler.option.debugging.level.1633475294" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1614770923" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.301173203" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1152604941" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1534571725" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1417897260" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
<tool id="cdt.managedbuild.tool.gnu.cross.assembler.206754207" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.2135072614" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
<cconfiguration id="cdt.managedbuild.config.gnu.cross.exe.release.1308789762">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.cross.exe.release.1308789762" moduleId="org.eclipse.cdt.core.settings" name="Release">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.cross.exe.release.1308789762" name="Release" parent="cdt.managedbuild.config.gnu.cross.exe.release">
<folderInfo id="cdt.managedbuild.config.gnu.cross.exe.release.1308789762." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.cross.exe.release.2089802121" name="Cross GCC" superClass="cdt.managedbuild.toolchain.gnu.cross.exe.release">
<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.321811258" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
<builder buildPath="${workspace_loc:/concurrency-in-action}/Release" id="cdt.managedbuild.builder.gnu.cross.581862874" managedBuildOn="true" name="Gnu Make Builder.Release" superClass="cdt.managedbuild.builder.gnu.cross"/>
<tool id="cdt.managedbuild.tool.gnu.cross.c.compiler.1263617891" name="Cross GCC Compiler" superClass="cdt.managedbuild.tool.gnu.cross.c.compiler">
<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.option.optimization.level.1570617197" superClass="gnu.c.compiler.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/>
<option defaultValue="gnu.c.debugging.level.none" id="gnu.c.compiler.option.debugging.level.1573251332" superClass="gnu.c.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1569558056" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.1348481540" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
<option id="gnu.cpp.compiler.option.optimization.level.100340695" superClass="gnu.cpp.compiler.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
<option defaultValue="gnu.cpp.compiler.debugging.level.none" id="gnu.cpp.compiler.option.debugging.level.584780047" superClass="gnu.cpp.compiler.option.debugging.level" useByScannerDiscovery="false" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1437636074" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.c.linker.170044107" name="Cross GCC Linker" superClass="cdt.managedbuild.tool.gnu.cross.c.linker"/>
<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1428396919" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.948393561" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
<additionalInput kind="additionalinput" paths="$(LIBS)"/>
</inputType>
</tool>
<tool id="cdt.managedbuild.tool.gnu.cross.archiver.1625798495" name="Cross GCC Archiver" superClass="cdt.managedbuild.tool.gnu.cross.archiver"/>
<tool id="cdt.managedbuild.tool.gnu.cross.assembler.70580537" name="Cross GCC Assembler" superClass="cdt.managedbuild.tool.gnu.cross.assembler">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.226212603" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="concurrency-in-action.cdt.managedbuild.target.gnu.cross.exe.508515326" name="Executable" projectType="cdt.managedbuild.target.gnu.cross.exe"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012;cdt.managedbuild.config.gnu.cross.exe.debug.1192994012.;cdt.managedbuild.tool.gnu.cross.c.compiler.680385655;cdt.managedbuild.tool.gnu.c.compiler.input.2123668139">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012;cdt.managedbuild.config.gnu.cross.exe.debug.1192994012.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.241274475;cdt.managedbuild.tool.gnu.cpp.compiler.input.1614770923">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.1308789762;cdt.managedbuild.config.gnu.cross.exe.release.1308789762.;cdt.managedbuild.tool.gnu.cross.cpp.compiler.1348481540;cdt.managedbuild.tool.gnu.cpp.compiler.input.1437636074">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.cross.exe.release.1308789762;cdt.managedbuild.config.gnu.cross.exe.release.1308789762.;cdt.managedbuild.tool.gnu.cross.c.compiler.1263617891;cdt.managedbuild.tool.gnu.c.compiler.input.1569558056">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>

27
.project Normal file
View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>concurrency-in-action</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project>
<configuration id="cdt.managedbuild.config.gnu.cross.exe.debug.1192994012" name="Debug">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="564395207262711818" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
<configuration id="cdt.managedbuild.config.gnu.cross.exe.release.1308789762" name="Release">
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
<provider class="org.eclipse.cdt.internal.build.crossgcc.CrossGCCBuiltinSpecsDetector" console="false" env-hash="564395207262711818" id="org.eclipse.cdt.build.crossgcc.CrossGCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>
</extension>
</configuration>
</project>

View File

@@ -1,18 +1,17 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
void hello() void
hello()
{ {
std::cout << "Hello Concurrent World\n"; std::cout << "Hello Concurrent World\n";
} }
int main() int
main()
{ {
//boost::thread t([]() // boost::thread t([]()
std::thread t([]() std::thread t([]() { std::cout << "Hello Concurrent World\n"; });
{
std::cout << "Hello Concurrent World\n";
});
t.join(); t.join();
} }

View File

@@ -1,69 +1,69 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <vector> #include <numeric> // std::accumulate
#include <thread> #include <thread>
#include <numeric> // std::accumulate #include <vector>
template <typename Iterator, typename T> template <typename Iterator, typename T>
struct accumulate_block struct accumulate_block {
{ void operator()(Iterator first, Iterator last, T& result)
void operator()(Iterator first, Iterator last, T& result) {
{ result = std::accumulate(first, last, result);
result = std::accumulate(first,last,result); }
}
}; };
template <typename Iterator, typename T> template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init) T
parallel_accumulate(Iterator first, Iterator last, T init)
{ {
unsigned long const length = std::distance(first,last); unsigned long const length = std::distance(first, last);
if (!length) return init; if (!length)
return init;
unsigned long const min_per_thread = 25; unsigned long const min_per_thread = 25;
unsigned long const max_threads = unsigned long const max_threads =
(length+min_per_thread-1)/min_per_thread; (length + min_per_thread - 1) / min_per_thread;
unsigned long const hardware_threads = unsigned long const hardware_threads = std::thread::hardware_concurrency();
std::thread::hardware_concurrency();
unsigned long const num_threads = unsigned long const num_threads =
std::min(hardware_threads != 0 ? hardware_threads:2, max_threads); std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);
unsigned long const block_size = length / num_threads; unsigned long const block_size = length / num_threads;
std::vector<T> results(num_threads); std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_threads-1); std::vector<std::thread> threads(num_threads - 1);
Iterator block_start = first; Iterator block_start = first;
for (unsigned long i = 0; i < (num_threads-1); ++i) for (unsigned long i = 0; i < (num_threads - 1); ++i) {
{ Iterator block_end = block_start;
Iterator block_end = block_start; std::advance(block_end, block_size);
std::advance(block_end,block_size); threads[i] = std::thread(accumulate_block<Iterator, T>(),
threads[i] = std::thread( block_start,
accumulate_block<Iterator,T>(), block_end,
block_start,block_end,std::ref(results[i])); std::ref(results[i]));
block_start = block_end; block_start = block_end;
} }
accumulate_block<std::vector<int>::iterator,int>()( accumulate_block<std::vector<int>::iterator, int>()(
block_start,last,results[num_threads-1]); block_start, last, results[num_threads - 1]);
std::for_each(threads.begin(),threads.end(), std::for_each(
std::mem_fn(&std::thread::join)); threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(),results.end(),init); return std::accumulate(results.begin(), results.end(), init);
} }
int main() int
main()
{ {
std::vector<int> numbers(50); std::vector<int> numbers(50);
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
numbers[i] = i; numbers[i] = i;
} }
int result = parallel_accumulate<std::vector<int>::iterator,int> int result = parallel_accumulate<std::vector<int>::iterator, int>(
(numbers.begin(),numbers.end(),0); numbers.begin(), numbers.end(), 0);
std::cout << "result: " << result << std::endl; std::cout << "result: " << result << std::endl;
} }

View File

@@ -1,57 +1,56 @@
#include <climits>
#include <mutex> #include <mutex>
#include <stdexcept> #include <stdexcept>
#include <climits>
class hierarchical_mutex class hierarchical_mutex {
{ std::mutex internal_mutex;
std::mutex internal_mutex; unsigned long const hierarchy_value;
unsigned long const hierarchy_value; unsigned long previous_hierarchy_value;
unsigned long previous_hierarchy_value; static thread_local unsigned long this_thread_hierarchy_value;
static thread_local unsigned long this_thread_hierarchy_value;
void check_for_hierarchy_violation() void check_for_hierarchy_violation()
{ {
if(this_thread_hierarchy_value <= hierarchy_value) if (this_thread_hierarchy_value <= hierarchy_value) {
{ throw std::logic_error("mutex hierarchy violated");
throw std::logic_error("mutex hierarchy violated");
}
}
void update_hierarchy_value()
{
previous_hierarchy_value=this_thread_hierarchy_value;
this_thread_hierarchy_value=hierarchy_value;
} }
}
void update_hierarchy_value()
{
previous_hierarchy_value = this_thread_hierarchy_value;
this_thread_hierarchy_value = hierarchy_value;
}
public: public:
explicit hierarchical_mutex(unsigned long value): explicit hierarchical_mutex(unsigned long value)
hierarchy_value(value), : hierarchy_value(value), previous_hierarchy_value(0)
previous_hierarchy_value(0) {
{} }
void lock() void lock()
{ {
check_for_hierarchy_violation(); check_for_hierarchy_violation();
internal_mutex.lock(); internal_mutex.lock();
update_hierarchy_value(); update_hierarchy_value();
} }
void unlock() void unlock()
{ {
this_thread_hierarchy_value=previous_hierarchy_value; this_thread_hierarchy_value = previous_hierarchy_value;
internal_mutex.unlock(); internal_mutex.unlock();
} }
bool try_lock() bool try_lock()
{ {
check_for_hierarchy_violation(); check_for_hierarchy_violation();
if(!internal_mutex.try_lock()) if (!internal_mutex.try_lock())
return false; return false;
update_hierarchy_value(); update_hierarchy_value();
return true; return true;
} }
}; };
thread_local unsigned long thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value(
hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX); ULONG_MAX);
int main() int
main()
{ {
hierarchical_mutex m1(42); hierarchical_mutex m1(42);
hierarchical_mutex m2(2000); hierarchical_mutex m2(2000);
} }

View File

@@ -1,68 +1,64 @@
#include <exception> #include <exception>
#include <stack>
#include <mutex>
#include <memory> #include <memory>
#include <mutex>
#include <stack>
struct empty_stack: std::exception struct empty_stack : std::exception {
{ const char* what() const throw() { return "empty stack"; }
const char* what() const throw()
{
return "empty stack";
}
}; };
template<typename T> template <typename T>
class threadsafe_stack class threadsafe_stack {
{
private: private:
std::stack<T> data; std::stack<T> data;
mutable std::mutex m; mutable std::mutex m;
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value) public:
{ threadsafe_stack() {}
std::lock_guard<std::mutex> lock(m); threadsafe_stack(const threadsafe_stack& other)
data.push(new_value); {
} std::lock_guard<std::mutex> lock(other.m);
std::shared_ptr<T> pop() data = other.data;
{ }
std::lock_guard<std::mutex> lock(m); threadsafe_stack& operator=(const threadsafe_stack&) = delete;
if(data.empty()) throw empty_stack();
std::shared_ptr<T> const res(std::make_shared<T>(data.top())); void push(T new_value)
data.pop(); {
return res; std::lock_guard<std::mutex> lock(m);
} data.push(new_value);
void pop(T& value) }
{ std::shared_ptr<T> pop()
std::lock_guard<std::mutex> lock(m); {
if(data.empty()) throw empty_stack(); std::lock_guard<std::mutex> lock(m);
value=data.top(); if (data.empty())
data.pop(); throw empty_stack();
} std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
bool empty() const data.pop();
{ return res;
std::lock_guard<std::mutex> lock(m); }
return data.empty(); void pop(T& value)
} {
std::lock_guard<std::mutex> lock(m);
if (data.empty())
throw empty_stack();
value = data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
}; };
int main() int
main()
{ {
threadsafe_stack<int> si; threadsafe_stack<int> si;
si.push(5); si.push(5);
si.pop(); si.pop();
if(!si.empty()) if (!si.empty()) {
{ int x;
int x; si.pop(x);
si.pop(x); }
}
} }

View File

@@ -1,104 +1,105 @@
#include <iostream> #include <condition_variable>
#include <cstdio> #include <cstdio>
#include <queue> #include <iostream>
#include <thread>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <condition_variable> #include <queue>
#include <thread>
template <typename T> template <typename T>
class queue class queue {
{ private:
private: mutable std::mutex mut;
mutable std::mutex mut; std::queue<T> data_queue;
std::queue<T> data_queue; std::condition_variable data_cond;
std::condition_variable data_cond;
public: public:
queue(){} queue() {}
queue(const queue& other) queue(const queue& other)
{ {
std::lock_guard<std::mutex> lk(other.mut); std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue; data_queue = other.data_queue;
}
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this] { return !data_queue.empty(); });
value = data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this] { return !data_queue.empty(); });
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
return false;
} }
value = data_queue.front();
data_queue.pop();
return true;
}
void push(T new_value) std::shared_ptr<T> try_pop()
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value); if (data_queue.empty()) {
data_cond.notify_one(); return std::shared_ptr<T>();
} }
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
void wait_and_pop(T& value) bool empty() const
{ {
std::unique_lock<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();}); return data_queue.empty();
value = data_queue.front(); }
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]{return !data_queue.empty();});
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool try_pop(T& value)
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
return false;
}
value = data_queue.front();
data_queue.pop();
return true;
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) {
return std::shared_ptr<T>();
}
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
}; };
void push(queue<int>* q) void
push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
//std::cout << "pushing " << i << std::endl; // std::cout << "pushing " << i << std::endl;
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
} }
} }
void pop(queue<int>* q) void
pop(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("poping %d\n", *q->wait_and_pop()); printf("poping %d\n", *q->wait_and_pop());
} }
}
int main()
{
queue<int> q;
std::thread t1(push,&q);
std::thread t2(pop,&q);
t1.join();
t2.join();
return 0;
} }
int
main()
{
queue<int> q;
std::thread t1(push, &q);
std::thread t2(pop, &q);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,74 +1,70 @@
#include <iostream>
#include <cstdio>
#include <list>
#include <thread>
#include <memory>
#include <algorithm> #include <algorithm>
#include <cstdio>
#include <future> #include <future>
#include <iostream>
#include <list>
#include <memory>
#include <thread>
std::ostream& operator<<(std::ostream& ostr, const std::list<int>& list) std::ostream&
operator<<(std::ostream& ostr, const std::list<int>& list)
{ {
for (auto &i : list) { for (auto& i : list) {
ostr << " " << i; ostr << " " << i;
} }
return ostr; return ostr;
} }
template<typename T> template <typename T>
std::list<T> sequential_quick_sort(std::list<T> input) std::list<T>
sequential_quick_sort(std::list<T> input)
{ {
if(input.empty()) if (input.empty()) {
{ return input;
return input; }
} std::list<T> result;
std::list<T> result; result.splice(result.begin(), input, input.begin());
result.splice(result.begin(),input,input.begin()); T const& pivot = *result.begin();
T const& pivot=*result.begin(); auto divide_point = std::partition(
auto divide_point=std::partition(input.begin(),input.end(), input.begin(), input.end(), [&](T const& t) { return t < pivot; });
[&](T const& t){return t<pivot;}); std::list<T> lower_part;
std::list<T> lower_part; lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
lower_part.splice(lower_part.end(),input,input.begin(), auto new_lower(sequential_quick_sort(std::move(lower_part)));
divide_point); auto new_higher(sequential_quick_sort(std::move(input)));
auto new_lower( result.splice(result.end(), new_higher);
sequential_quick_sort(std::move(lower_part))); result.splice(result.begin(), new_lower);
auto new_higher( return result;
sequential_quick_sort(std::move(input)));
result.splice(result.end(),new_higher);
result.splice(result.begin(),new_lower);
return result;
} }
template<typename T> template <typename T>
std::list<T> parallel_quick_sort(std::list<T> input) std::list<T>
parallel_quick_sort(std::list<T> input)
{ {
if(input.empty()) if (input.empty()) {
{ return input;
return input; }
} std::list<T> result;
std::list<T> result; result.splice(result.begin(), input, input.begin());
result.splice(result.begin(),input,input.begin()); T const& pivot = *result.begin();
T const& pivot=*result.begin(); auto divide_point = std::partition(
auto divide_point=std::partition(input.begin(),input.end(), input.begin(), input.end(), [&](T const& t) { return t < pivot; });
[&](T const& t){return t<pivot;}); std::list<T> lower_part;
std::list<T> lower_part; lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
lower_part.splice(lower_part.end(),input,input.begin(), std::future<std::list<T>> new_lower(
divide_point); std::async(&parallel_quick_sort<T>, std::move(lower_part)));
std::future<std::list<T> > new_lower( auto new_higher(parallel_quick_sort(std::move(input)));
std::async(&parallel_quick_sort<T>,std::move(lower_part))); result.splice(result.end(), new_higher);
auto new_higher( result.splice(result.begin(), new_lower.get());
parallel_quick_sort(std::move(input))); return result;
result.splice(result.end(),new_higher);
result.splice(result.begin(),new_lower.get());
return result;
} }
int main() int
main()
{ {
std::list<int> list1 = {4, 2, 1, 5, 8, 9, 7}; std::list<int> list1 = {4, 2, 1, 5, 8, 9, 7};
std::list<int> sorted1 = sequential_quick_sort(list1); std::list<int> sorted1 = sequential_quick_sort(list1);
std::list<int> sorted2 = parallel_quick_sort(list1); std::list<int> sorted2 = parallel_quick_sort(list1);
std::cout << "sorted1: " << sorted1 << std::endl; std::cout << "sorted1: " << sorted1 << std::endl;
std::cout << "sorted2: " << sorted2 << std::endl; std::cout << "sorted2: " << sorted2 << std::endl;
return 0; return 0;
} }

View File

@@ -1,126 +1,115 @@
#include <iostream>
#include <thread>
#include <memory>
#include <cstdio> #include <cstdio>
#include <iostream>
#include <memory>
#include <thread>
template <typename T> template <typename T>
class list class list {
{ struct node {
struct node std::mutex m;
{ std::shared_ptr<T> data;
std::mutex m; std::unique_ptr<node> next;
std::shared_ptr<T> data;
std::unique_ptr<node> next;
node() node() : next() {}
: next()
{}
node(T const& value)
: data(std::make_shared<T>(value))
{}
};
node head; node(T const& value) : data(std::make_shared<T>(value)) {}
};
public: node head;
list()
{}
~list() public:
{ list() {}
remove_if([](T const&){return true;});
~list()
{
remove_if([](T const&) { return true; });
}
list(list const& other) = delete;
list& operator=(list const& other) = delete;
void push_front(T const& value)
{
std::unique_ptr<node> new_node(new node(value));
std::lock_guard<std::mutex> lk(head.m);
new_node->next = std::move(head.next);
head.next = std::move(new_node);
}
template <typename Function>
void for_each(Function f)
{
node* current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get()) {
std::unique_lock<std::mutex> next_lk(next->m);
lk.unlock();
f(*next->data);
current = next;
lk = std::move(next_lk);
} }
}
list(list const& other) = delete; template <typename Predicate>
list& operator=(list const& other) = delete; std::shared_ptr<T> find_first_of(Predicate p)
{
void push_front(T const& value) node* current = &head;
{ std::unique_lock<std::mutex> lk(head.m);
std::unique_ptr<node> new_node(new node(value)); while (node* const next = current->next.get()) {
std::lock_guard<std::mutex> lk(head.m); std::unique_lock<std::mutex> next_lk(next->m);
new_node->next = std::move(head.next); lk.unlock();
head.next = std::move(new_node); if (p(*next->data)) {
return next->data;
}
current = next;
lk = std::move(next_lk);
} }
return std::shared_ptr<T>();
}
template <typename Function> template <typename Predicate>
void for_each(Function f) void remove_if(Predicate p)
{ {
node* current = &head; node* current = &head;
std::unique_lock<std::mutex> lk(head.m); std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get()) while (node* const next = current->next.get()) {
{ std::unique_lock<std::mutex> next_lk(next->m);
std::unique_lock<std::mutex> next_lk(next->m); if (p(*next->data)) {
lk.unlock(); std::unique_ptr<node> old_next = std::move(current->next);
f(*next->data); current->next = std::move(next->next);
current = next; next_lk.unlock();
lk = std::move(next_lk); }
} else {
} lk.unlock();
current = next;
template <typename Predicate> lk = std::move(next_lk);
std::shared_ptr<T> find_first_of(Predicate p) }
{
node *current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get())
{
std::unique_lock<std::mutex> next_lk(next->m);
lk.unlock();
if (p(*next->data))
{
return next->data;
}
current = next;
lk = std::move(next_lk);
}
return std::shared_ptr<T>();
}
template <typename Predicate>
void remove_if(Predicate p)
{
node *current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get())
{
std::unique_lock<std::mutex> next_lk(next->m);
if (p(*next->data))
{
std::unique_ptr<node> old_next = std::move(current->next);
current->next = std::move(next->next);
next_lk.unlock();
}
else
{
lk.unlock();
current = next;
lk = std::move(next_lk);
}
}
} }
}
}; };
void push(list<int>* l) void
push(list<int>* l)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
l->push_front(i); l->push_front(i);
} }
} }
void visit(int i) void
visit(int i)
{ {
printf("visit %d\n", i); printf("visit %d\n", i);
}
int main()
{
list<int> l;
std::thread t(push,&l);
sleep(1);
l.for_each(visit);
t.join();
return 0;
} }
int
main()
{
list<int> l;
std::thread t(push, &l);
sleep(1);
l.for_each(visit);
t.join();
return 0;
}

View File

@@ -1,133 +1,122 @@
#include <boost/thread/shared_mutex.hpp>
#include <iostream> #include <iostream>
#include <list>
#include <memory>
#include <string> #include <string>
#include <thread> #include <thread>
#include <boost/thread/shared_mutex.hpp>
#include <memory>
#include <list>
#include <vector> #include <vector>
template <typename Key, typename Value, typename Hash=std::hash<Key> > template <typename Key, typename Value, typename Hash = std::hash<Key>>
class lookup_table class lookup_table {
{ private:
class bucket_type {
private: private:
class bucket_type typedef std::pair<Key, Value> bucket_value;
typedef std::list<bucket_value> bucket_data;
typedef typename bucket_data::iterator bucket_iterator;
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const
{ {
private: return std::find_if(
typedef std::pair<Key, Value> bucket_value; data.begin(), data.end(), [&](bucket_value const& item) {
typedef std::list<bucket_value> bucket_data; return item.first == key;
typedef typename bucket_data::iterator bucket_iterator; });
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const
{
return std::find_if(data.begin(), data.end(),
[&](bucket_value const& item)
{return item.first == key;});
}
public:
Value value_for(Key const& key, Value const& default_value) const
{
boost::shared_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
return (found_entry == data.end()) ?
default_value : found_entry->second;
}
void add_or_update_mapping(Key const& key, Value const& value)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry == data.end()) {
data.push_back(bucket_value(key,value));
}
else {
found_entry->second = value;
}
}
void remove_mapping(Key const& key)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry != data.end()) {
data.erase(found_entry);
}
}
};
std::vector<std::unique_ptr<bucket_type> > buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
const std::size_t bucket_index = hasher(key) % buckets.size();
return *buckets[bucket_index];
} }
public: public:
typedef Key key_type; Value value_for(Key const& key, Value const& default_value) const
typedef Value mapped_type;
typedef Hash hash_type;
lookup_table(unsigned num_buckets = 19, const Hash& hasher_ = Hash())
: buckets(num_buckets)
, hasher(hasher_)
{ {
for (unsigned i = 0; i < num_buckets; ++i) boost::shared_lock<boost::shared_mutex> lock(mutex);
{ bucket_iterator const found_entry = find_entry_for(key);
buckets[i].reset(new bucket_type); return (found_entry == data.end()) ? default_value : found_entry->second;
}
} }
lookup_table(const lookup_table& other) = delete; void add_or_update_mapping(Key const& key, Value const& value)
lookup_table& operator=(const lookup_table& other) = delete;
Value value_for(Key const& key,
Value const& default_value = Value()) const
{ {
return get_bucket(key).value_for(key, default_value); std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry == data.end()) {
data.push_back(bucket_value(key, value));
}
else {
found_entry->second = value;
}
} }
void add_or_update_mapping(const Key& key, const Value& value) void remove_mapping(Key const& key)
{ {
get_bucket(key).add_or_update_mapping(key, value); std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry != data.end()) {
data.erase(found_entry);
}
} }
};
void remove_mapping(const Key& key) std::vector<std::unique_ptr<bucket_type>> buckets;
{ Hash hasher;
get_bucket(key).remove_mapping(key);
}
std::map<Key,Value> get_map() const bucket_type& get_bucket(Key const& key) const
{ {
std::vector<boost::unique_lock<boost::shared_mutex> > locks; const std::size_t bucket_index = hasher(key) % buckets.size();
for (unsigned i = 0; i < buckets.size(); ++i) return *buckets[bucket_index];
{ }
locks.push_back(boost::unique_lock<boost::shared_mutex>(
buckets[i].mutex)); public:
} typedef Key key_type;
std::map<Key,Value> res; typedef Value mapped_type;
for (unsigned i = 0; i < buckets.size(); ++i) typedef Hash hash_type;
{
for (typename bucket_type::bucket_iterator it = buckets[i].data.begin(); lookup_table(unsigned num_buckets = 19, const Hash& hasher_ = Hash())
it != buckets[i].data.end(); : buckets(num_buckets), hasher(hasher_)
++it) {
{ for (unsigned i = 0; i < num_buckets; ++i) {
res.insert(*it); buckets[i].reset(new bucket_type);
}
}
return res;
} }
}
lookup_table(const lookup_table& other) = delete;
lookup_table& operator=(const lookup_table& other) = delete;
Value value_for(Key const& key, Value const& default_value = Value()) const
{
return get_bucket(key).value_for(key, default_value);
}
void add_or_update_mapping(const Key& key, const Value& value)
{
get_bucket(key).add_or_update_mapping(key, value);
}
void remove_mapping(const Key& key) { get_bucket(key).remove_mapping(key); }
std::map<Key, Value> get_map() const
{
std::vector<boost::unique_lock<boost::shared_mutex>> locks;
for (unsigned i = 0; i < buckets.size(); ++i) {
locks.push_back(
boost::unique_lock<boost::shared_mutex>(buckets[i].mutex));
}
std::map<Key, Value> res;
for (unsigned i = 0; i < buckets.size(); ++i) {
for (typename bucket_type::bucket_iterator it = buckets[i].data.begin();
it != buckets[i].data.end();
++it) {
res.insert(*it);
}
}
return res;
}
}; };
int main() int
main()
{ {
lookup_table<int,std::string> t; lookup_table<int, std::string> t;
t.add_or_update_mapping(1,"hello"); t.add_or_update_mapping(1, "hello");
std::cout << "value for 1 is " << t.value_for(1) << std::endl; std::cout << "value for 1 is " << t.value_for(1) << std::endl;
return 0; return 0;
} }

View File

@@ -1,112 +1,113 @@
#include <iostream> #include <condition_variable>
#include <cstdio> #include <cstdio>
#include <queue> #include <iostream>
#include <thread>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <condition_variable> #include <queue>
#include <thread>
template <typename T> template <typename T>
class queue class queue {
{ private:
private: mutable std::mutex mut;
mutable std::mutex mut; std::queue<std::shared_ptr<T>> data_queue;
std::queue<std::shared_ptr<T> > data_queue; std::condition_variable data_cond;
std::condition_variable data_cond;
public: public:
queue(){} queue() {}
queue(const queue& other) queue(const queue& other)
{ {
std::lock_guard<std::mutex> lk(other.mut); std::lock_guard<std::mutex> lk(other.mut);
data_queue = other.data_queue; data_queue = other.data_queue;
}
void push(T new_value)
{
std::shared_ptr<T> data(new T(new_value));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [&] { return !data_queue.empty(); });
/*
while (data_queue.empty()) {
data_cond.wait(lk);
} }
*/
value = *data_queue.front();
data_queue.pop();
}
void push(T new_value) std::shared_ptr<T> wait_and_pop()
{ {
std::shared_ptr<T> data(new T(new_value)); std::unique_lock<std::mutex> lk(mut);
std::lock_guard<std::mutex> lk(mut); data_cond.wait(lk, [&] { return !data_queue.empty(); });
data_queue.push(data); /*
data_cond.notify_one(); while (data_queue.empty()) {
data_cond.wait(lk);
} }
*/
std::shared_ptr<T> res = data_queue.front();
data_queue.pop();
return res;
}
void wait_and_pop(T& value) bool try_pop(T& value)
{ {
std::unique_lock<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_cond.wait(lk, [&]{return !data_queue.empty();}); if (data_queue.empty())
/* return false;
while (data_queue.empty()) { value = *data_queue.front();
data_cond.wait(lk); data_queue.pop();
} }
*/
value = *data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> wait_and_pop() std::shared_ptr<T> try_pop()
{ {
std::unique_lock<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_cond.wait(lk, [&]{return !data_queue.empty();}); if (data_queue.empty())
/* return std::shared_ptr<T>();
while (data_queue.empty()) { std::shared_ptr<T> res = data_queue.front();
data_cond.wait(lk); data_queue.pop();
} return res;
*/ }
std::shared_ptr<T> res = data_queue.front();
data_queue.pop();
return res;
}
bool try_pop(T& value) bool empty() const
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty()) return data_queue.empty();
return false; }
value = *data_queue.front();
data_queue.pop();
}
std::shared_ptr<T> try_pop()
{
std::lock_guard<std::mutex> lk(mut);
if (data_queue.empty())
return std::shared_ptr<T>();
std::shared_ptr<T> res = data_queue.front();
data_queue.pop();
return res;
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
}; };
void push(queue<int>* q) void
push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
//std::cout << "pushing " << i << std::endl; // std::cout << "pushing " << i << std::endl;
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
} }
} }
void pop(queue<int>* q) void
pop(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("poping %d\n", *q->wait_and_pop()); printf("poping %d\n", *q->wait_and_pop());
} }
}
int main()
{
queue<int> q;
std::thread t1(push,&q);
std::thread t2(pop,&q);
t1.join();
t2.join();
return 0;
} }
int
main()
{
queue<int> q;
std::thread t1(push, &q);
std::thread t2(pop, &q);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,94 +1,93 @@
#include <iostream> #include <iostream>
#include <queue>
#include <memory> #include <memory>
#include <thread>
#include <mutex> #include <mutex>
#include <queue>
#include <thread>
template <typename T> template <typename T>
class queue class queue {
{ private:
private: struct node {
struct node std::shared_ptr<T> data;
{ std::unique_ptr<node> next;
std::shared_ptr<T> data; };
std::unique_ptr<node> next;
};
std::mutex head_mutex; std::mutex head_mutex;
std::unique_ptr<node> head; std::unique_ptr<node> head;
std::mutex tail_mutex; std::mutex tail_mutex;
node *tail; node* tail;
node *get_tail() node* get_tail()
{ {
std::lock_guard<std::mutex> tail_lock(tail_mutex); std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail; return tail;
}
std::unique_ptr<node> pop_head()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return nullptr;
} }
std::unique_ptr<node> old_head = std::move(head);
head = std::move(old_head->next);
return old_head;
}
std::unique_ptr<node> pop_head() public:
{ queue() : head(new node), tail(head.get()) {}
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return nullptr;
}
std::unique_ptr<node> old_head = std::move(head);
head = std::move(old_head->next);
return old_head;
}
public: queue(const queue& other) = delete;
queue():head(new node),tail(head.get()) queue& operator=(const queue& other) = delete;
{}
queue(const queue& other) = delete; std::shared_ptr<T> try_pop()
queue& operator=(const queue& other) = delete; {
std::unique_ptr<node> old_head = pop_head();
return old_head ? old_head->data : std::shared_ptr<T>();
}
std::shared_ptr<T> try_pop() void push(T new_value)
{ {
std::unique_ptr<node> old_head = pop_head(); std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
return old_head ? old_head->data : std::shared_ptr<T>(); std::unique_ptr<node> p(new node);
} node* const new_tail = p.get();
std::lock_guard<std::mutex> tail_lock(tail_mutex);
void push(T new_value) tail->data = new_data;
{ tail->next = std::move(p);
std::shared_ptr<T> new_data( tail = new_tail;
std::make_shared<T>(std::move(new_value))); }
std::unique_ptr<node> p(new node);
node *const new_tail = p.get();
std::lock_guard<std::mutex> tail_lock(tail_mutex);
tail->data = new_data;
tail->next = std::move(p);
tail = new_tail;
}
}; };
void push(queue<int>* q) void
push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
}
}
void
pop(queue<int>* q)
{
int i = 0;
while (true) {
if (std::shared_ptr<int> p = q->try_pop()) {
printf("poping %d\n", *p);
++i;
} }
if (i == 10)
break;
}
} }
void pop(queue<int>* q) int
main()
{ {
int i = 0; queue<int> q;
while (true) { std::thread th1(push, &q);
if (std::shared_ptr<int> p = q->try_pop()) { std::thread th2(pop, &q);
printf("poping %d\n", *p); th1.join();
++i; th2.join();
} return 0;
if (i == 10) break;
}
} }
int main()
{
queue<int> q;
std::thread th1(push,&q);
std::thread th2(pop,&q);
th1.join();
th2.join();
return 0;
}

View File

@@ -1,154 +1,151 @@
#include <iostream>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
template <typename T> template <typename T>
class queue class queue {
{ private:
private: struct node {
struct node std::shared_ptr<T> data;
{ std::unique_ptr<node> next;
std::shared_ptr<T> data; };
std::unique_ptr<node> next;
};
std::mutex head_mutex; std::mutex head_mutex;
std::unique_ptr<node> head; std::unique_ptr<node> head;
std::mutex tail_mutex; std::mutex tail_mutex;
node *tail; node* tail;
std::condition_variable data_cond; std::condition_variable data_cond;
node *get_tail() node* get_tail()
{ {
std::lock_guard<std::mutex> tail_lock(tail_mutex); std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail; return tail;
}
std::unique_ptr<node> pop_head()
{
std::unique_ptr<node> old_head = std::move(head);
head = std::move(old_head->next);
return old_head;
}
std::unique_ptr<node> try_pop_head()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return std::unique_ptr<node>();
} }
return pop_head();
}
std::unique_ptr<node> pop_head() std::unique_ptr<node> try_pop_head(T& value)
{ {
std::unique_ptr<node> old_head = std::move(head); std::lock_guard<std::mutex> head_lock(head_mutex);
head = std::move(old_head->next); if (head.get() == get_tail()) {
return old_head; return std::unique_ptr<node>();
} }
value = std::move(*head->data);
return pop_head();
}
std::unique_ptr<node> try_pop_head() std::unique_lock<std::mutex> wait_for_data()
{
std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock, [&] { return head.get() != queue::get_tail(); });
return std::move(head_lock);
}
std::unique_ptr<node> wait_pop_head()
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
return pop_head();
}
std::unique_ptr<node> wait_pop_head(T& value)
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
value = std::move(*head->data);
return pop_head();
}
public:
queue() : head(new node), tail(head.get()) {}
queue(const queue& other) = delete;
queue& operator=(const queue& other) = delete;
std::shared_ptr<T> try_pop()
{
std::unique_ptr<node> old_head = try_pop_head();
return old_head ? old_head->data : std::shared_ptr<T>();
}
bool try_pop(T& value)
{
std::unique_ptr<node> const old_head = try_pop_head(value);
return old_head;
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_ptr<node> const old_head = wait_pop_head();
return old_head->data;
}
void wait_and_pop(T& value)
{
std::unique_ptr<node> const old_head = wait_pop_value(value);
}
void push(T new_value)
{
std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
{ {
std::lock_guard<std::mutex> head_lock(head_mutex); std::lock_guard<std::mutex> tail_lock(tail_mutex);
if (head.get() == get_tail()) { tail->data = new_data;
return std::unique_ptr<node>(); node* const new_tail = p.get();
} tail->next = std::move(p);
return pop_head(); tail = new_tail;
} }
data_cond.notify_one();
}
std::unique_ptr<node> try_pop_head(T& value) void empty()
{ {
std::lock_guard<std::mutex> head_lock(head_mutex); std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) { return (head.get(0 == get_tail()));
return std::unique_ptr<node>(); }
}
value = std::move(*head->data);
return pop_head();
}
std::unique_lock<std::mutex> wait_for_data()
{
std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock, [&]{return head.get() != queue::get_tail();});
return std::move(head_lock);
}
std::unique_ptr<node> wait_pop_head()
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
return pop_head();
}
std::unique_ptr<node> wait_pop_head(T& value)
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
value = std::move(*head->data);
return pop_head();
}
public:
queue():head(new node),tail(head.get())
{}
queue(const queue& other) = delete;
queue& operator=(const queue& other) = delete;
std::shared_ptr<T> try_pop()
{
std::unique_ptr<node> old_head = try_pop_head();
return old_head ? old_head->data : std::shared_ptr<T>();
}
bool try_pop(T& value)
{
std::unique_ptr<node> const old_head = try_pop_head(value);
return old_head;
}
std::shared_ptr<T> wait_and_pop()
{
std::unique_ptr<node> const old_head = wait_pop_head();
return old_head->data;
}
void wait_and_pop(T& value)
{
std::unique_ptr<node> const old_head = wait_pop_value(value);
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
tail->data = new_data;
node *const new_tail = p.get();
tail->next = std::move(p);
tail = new_tail;
}
data_cond.notify_one();
}
void empty()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
return (head.get(0 == get_tail()));
}
}; };
void
void push(queue<int>* q) push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
} }
} }
void pop(queue<int>* q) void
pop(queue<int>* q)
{ {
int i = 0; int i = 0;
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("poping %d\n", *q->wait_and_pop()); printf("poping %d\n", *q->wait_and_pop());
} }
} }
int main() int
main()
{ {
queue<int> q; queue<int> q;
std::thread th1(push,&q); std::thread th1(push, &q);
std::thread th2(pop,&q); std::thread th2(pop, &q);
th1.join(); th1.join();
th2.join(); th2.join();
return 0; return 0;
} }

View File

@@ -1,62 +1,63 @@
#include <exception> #include <exception>
#include <iostream> #include <iostream>
#include <stack>
#include <memory> #include <memory>
#include <thread>
#include <mutex> #include <mutex>
#include <stack>
#include <thread>
template <typename T> template <typename T>
class stack class stack {
{ private:
private: std::stack<T> data;
std::stack<T> data; mutable std::mutex m;
mutable std::mutex m;
public: public:
stack(){} stack() {}
stack(const stack& other) stack(const stack& other)
{ {
std::lock_guard<std::mutex> lock(other.m); std::lock_guard<std::mutex> lock(other.m);
data = other.data; data = other.data;
} }
stack& operator=(const stack&) = delete; stack& operator=(const stack&) = delete;
void push(T new_value) void push(T new_value)
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
data.push(new_value); data.push(new_value);
} }
std::shared_ptr<T> pop() std::shared_ptr<T> pop()
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
if (data.empty()) throw std::underflow_error("empty stack"); if (data.empty())
std::shared_ptr<T> const res(new T(data.top())); throw std::underflow_error("empty stack");
data.pop(); std::shared_ptr<T> const res(new T(data.top()));
return res; data.pop();
} return res;
}
void pop(T& value) void pop(T& value)
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
if (data.empty()) throw std::underflow_error("empty stack"); if (data.empty())
value = data.top(); throw std::underflow_error("empty stack");
data.pop(); value = data.top();
} data.pop();
}
bool empty() const bool empty() const
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
return data.empty(); return data.empty();
} }
}; };
int main() int
main()
{ {
stack<int> s; stack<int> s;
s.push(1); s.push(1);
std::cout << *s.pop() << std::endl; std::cout << *s.pop() << std::endl;
} }

View File

@@ -1,63 +1,53 @@
#include <cstdio>
#include <memory> #include <memory>
#include <thread> #include <thread>
#include <cstdio>
unsigned const max_hazard_pointers = 100; unsigned const max_hazard_pointers = 100;
struct hazard_pointer struct hazard_pointer {
{ std::atomic<std::thread::id> id;
std::atomic<std::thread::id> id; std::atomic<void*> pointer;
std::atomic<void*> pointer;
}; };
hazard_pointer hazard_pointers[max_hazard_pointers]; hazard_pointer hazard_pointers[max_hazard_pointers];
class hp_owner class hp_owner {
{ hazard_pointer* hp;
hazard_pointer* hp;
public: public:
hp_owner(hp_owner const&)=delete; hp_owner(hp_owner const&) = delete;
hp_owner operator=(hp_owner const&)=delete; hp_owner operator=(hp_owner const&) = delete;
hp_owner() hp_owner() : hp(nullptr)
: hp(nullptr) {
{ for (unsigned i = 0; i < max_hazard_pointers; ++i) {
for (unsigned i = 0; i < max_hazard_pointers; ++i) { std::thread::id old_id;
std::thread::id old_id; // try to claim ownership of a hazard pointer
// try to claim ownership of a hazard pointer if (hazard_pointers[i].id.compare_exchange_strong(
if (hazard_pointers[i].id.compare_exchange_strong( old_id, std::this_thread::get_id())) {
old_id, std::this_thread::get_id())) { // successfully claimed the entry for the current thread,
// successfully claimed the entry for the current thread, // store it and stop the search
// store it and stop the search hp = &hazard_pointers[i];
hp = &hazard_pointers[i]; printf("hp: %ld\n", hp);
printf("hp: %ld\n", hp); break;
break; }
} // another threads owns this entry, move on to the next
// another threads owns this entry, move on to the next
}
// if you get to the end of the list without finding a free entry,
// there are too many threads using hazard pointers, so throw an
// exception
if (!hp) {
throw std::runtime_error("No hazard pointers available");
}
} }
// if you get to the end of the list without finding a free entry,
// there are too many threads using hazard pointers, so throw an
// exception
if (!hp) {
throw std::runtime_error("No hazard pointers available");
}
}
std::atomic<void*>& get_pointer() std::atomic<void*>& get_pointer() { return hp->pointer; }
{
return hp->pointer;
}
~hp_owner() ~hp_owner()
{ {
// when each thread exits, if an instance of hp_owner was created // when each thread exits, if an instance of hp_owner was created
// for the thread, then it's destryoed. The destructor then resets // for the thread, then it's destryoed. The destructor then resets
// the actual pointer to nullptr before setting the owner ID to // the actual pointer to nullptr before setting the owner ID to
// std::thread::id(), allowing another thread to reuse the entry later. // std::thread::id(), allowing another thread to reuse the entry later.
// TODO: this causes crash // TODO: this causes crash
//hp->pointer.store(nullptr); // hp->pointer.store(nullptr);
//hp->id.store(std::thread::id()); // hp->id.store(std::thread::id());
} }
}; };

View File

@@ -1,6 +1,6 @@
#include <iostream>
#include <cstdio>
#include <atomic> #include <atomic>
#include <cstdio>
#include <iostream>
#include <memory> #include <memory>
#include <thread> #include <thread>
@@ -9,232 +9,210 @@
// mpmc queue // mpmc queue
template <typename T> template <typename T>
class queue class queue {
{ private:
private: struct node;
struct node; struct counted_node_ptr {
struct counted_node_ptr int external_count;
node* ptr;
};
std::atomic<counted_node_ptr> head;
std::atomic<counted_node_ptr> tail;
struct node_counter {
unsigned internal_count : 30;
unsigned external_counters : 2;
// you need only 2 bits because there are at most two such
// counters (next and tail)
};
struct node {
std::atomic<T*> data;
std::atomic<node_counter> count;
std::atomic<counted_node_ptr> next;
node()
{ {
int external_count; node_counter new_count;
node* ptr; new_count.internal_count = 0;
}; new_count.external_counters = 2;
// because every node starts out referenced from tail and
// from the next pointer of the previous node once you've
// actually aadded it to the queue
count.store(new_count);
std::atomic<counted_node_ptr> head; counted_node_ptr new_next;
std::atomic<counted_node_ptr> tail; new_next.ptr = nullptr;
new_next.external_count = 0;
struct node_counter next.store(new_next);
{
unsigned internal_count:30;
unsigned external_counters:2;
// you need only 2 bits because there are at most two such
// counters (next and tail)
};
struct node
{
std::atomic<T*> data;
std::atomic<node_counter> count;
std::atomic<counted_node_ptr> next;
node()
{
node_counter new_count;
new_count.internal_count = 0;
new_count.external_counters = 2;
// because every node starts out referenced from tail and
// from the next pointer of the previous node once you've
// actually aadded it to the queue
count.store(new_count);
counted_node_ptr new_next;
new_next.ptr = nullptr;
new_next.external_count = 0;
next.store(new_next);
}
void release_ref()
{
node_counter old_counter=
count.load(std::memory_order_relaxed);
node_counter new_counter;
do
{
new_counter=old_counter;
--new_counter.internal_count;
}
while(!count.compare_exchange_strong(
old_counter,new_counter,
std::memory_order_acquire,std::memory_order_relaxed));
if(!new_counter.internal_count &&
!new_counter.external_counters)
{
delete this;
}
}
};
void set_new_tail(counted_node_ptr &old_tail,
counted_node_ptr const &new_tail)
{
node* const current_tail_ptr = old_tail.ptr;
while(!tail.compare_exchange_weak(old_tail,new_tail) &&
old_tail.ptr == current_tail_ptr);
if(old_tail.ptr == current_tail_ptr)
free_external_counter(old_tail);
else
current_tail_ptr->release_ref();
} }
static void increase_external_count( void release_ref()
std::atomic<counted_node_ptr>& counter,
counted_node_ptr& old_counter)
{ {
counted_node_ptr new_counter; node_counter old_counter = count.load(std::memory_order_relaxed);
do node_counter new_counter;
{ do {
new_counter = old_counter; new_counter = old_counter;
++new_counter.external_count; --new_counter.internal_count;
} } while (!count.compare_exchange_strong(old_counter,
while(!counter.compare_exchange_strong( new_counter,
old_counter,new_counter, std::memory_order_acquire,
std::memory_order_acquire,std::memory_order_relaxed)); std::memory_order_relaxed));
old_counter.external_count = new_counter.external_count; if (!new_counter.internal_count && !new_counter.external_counters) {
delete this;
}
} }
};
static void free_external_counter(counted_node_ptr &old_node_ptr) void set_new_tail(counted_node_ptr& old_tail,
{ counted_node_ptr const& new_tail)
node* const ptr = old_node_ptr.ptr; {
int const count_increase = old_node_ptr.external_count-2; node* const current_tail_ptr = old_tail.ptr;
node_counter old_counter = while (!tail.compare_exchange_weak(old_tail, new_tail) &&
ptr->count.load(std::memory_order_relaxed); old_tail.ptr == current_tail_ptr)
node_counter new_counter; ;
do if (old_tail.ptr == current_tail_ptr)
{ free_external_counter(old_tail);
new_counter=old_counter; else
--new_counter.external_counters; current_tail_ptr->release_ref();
new_counter.internal_count+=count_increase; }
}
while(!ptr->count.compare_exchange_strong( static void increase_external_count(std::atomic<counted_node_ptr>& counter,
old_counter,new_counter, counted_node_ptr& old_counter)
std::memory_order_acquire,std::memory_order_relaxed)); {
if(!new_counter.internal_count && counted_node_ptr new_counter;
!new_counter.external_counters) do {
{ new_counter = old_counter;
delete ptr; ++new_counter.external_count;
} } while (!counter.compare_exchange_strong(old_counter,
new_counter,
std::memory_order_acquire,
std::memory_order_relaxed));
old_counter.external_count = new_counter.external_count;
}
static void free_external_counter(counted_node_ptr& old_node_ptr)
{
node* const ptr = old_node_ptr.ptr;
int const count_increase = old_node_ptr.external_count - 2;
node_counter old_counter = ptr->count.load(std::memory_order_relaxed);
node_counter new_counter;
do {
new_counter = old_counter;
--new_counter.external_counters;
new_counter.internal_count += count_increase;
} while (!ptr->count.compare_exchange_strong(old_counter,
new_counter,
std::memory_order_acquire,
std::memory_order_relaxed));
if (!new_counter.internal_count && !new_counter.external_counters) {
delete ptr;
} }
}
public: public:
queue() queue() : head(), tail() {}
: head()
, tail()
{}
queue(const queue& other)=delete; queue(const queue& other) = delete;
queue& operator=(const queue& other)=delete; queue& operator=(const queue& other) = delete;
~queue() ~queue()
{ {
/* /*
while (node* const old_head = head.load()) { while (node* const old_head = head.load()) {
head.store(old_head->next); head.store(old_head->next);
delete old_head; delete old_head;
}
*/
} }
*/
}
void push(T new_value) void push(T new_value)
{ {
std::unique_ptr<T> new_data(new T(new_value)); std::unique_ptr<T> new_data(new T(new_value));
counted_node_ptr new_next; counted_node_ptr new_next;
new_next.ptr = new node; new_next.ptr = new node;
new_next.external_count=1; new_next.external_count = 1;
counted_node_ptr old_tail=tail.load(); counted_node_ptr old_tail = tail.load();
for(;;) for (;;) {
{ increase_external_count(tail, old_tail);
increase_external_count(tail,old_tail); T* old_data = nullptr;
T* old_data=nullptr; if (old_tail.ptr->data.compare_exchange_strong(old_data,
if(old_tail.ptr->data.compare_exchange_strong( new_data.get())) {
old_data,new_data.get())) counted_node_ptr old_next = {0};
{ if (!old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) {
counted_node_ptr old_next={0}; delete new_next.ptr;
if(!old_tail.ptr->next.compare_exchange_strong( new_next = old_next;
old_next,new_next))
{
delete new_next.ptr;
new_next=old_next;
}
set_new_tail(old_tail, new_next);
new_data.release();
break;
}
else
{
counted_node_ptr old_next={0};
if(old_tail.ptr->next.compare_exchange_strong(
old_next,new_next))
{
old_next=new_next;
new_next.ptr=new node;
}
set_new_tail(old_tail, old_next);
}
} }
} set_new_tail(old_tail, new_next);
new_data.release();
std::unique_ptr<T> pop() { break;
counted_node_ptr old_head = head.load(std::memory_order_relaxed); }
else {
for(;;) { counted_node_ptr old_next = {0};
increase_external_count(head, old_head); if (old_tail.ptr->next.compare_exchange_strong(old_next, new_next)) {
old_next = new_next;
node* const ptr = old_head.ptr; new_next.ptr = new node;
if (ptr==tail.load().ptr) {
ptr->release_ref();
return std::unique_ptr<T>();
}
counted_node_ptr next = ptr->next.load();
if (head.compare_exchange_strong(old_head, next)) {
T* const res=ptr->data.exchange(nullptr);
free_external_counter(old_head);
return std::unique_ptr<T>(res);
}
ptr->release_ref();
} }
set_new_tail(old_tail, old_next);
}
} }
}
std::unique_ptr<T> pop()
{
counted_node_ptr old_head = head.load(std::memory_order_relaxed);
for (;;) {
increase_external_count(head, old_head);
node* const ptr = old_head.ptr;
if (ptr == tail.load().ptr) {
ptr->release_ref();
return std::unique_ptr<T>();
}
counted_node_ptr next = ptr->next.load();
if (head.compare_exchange_strong(old_head, next)) {
T* const res = ptr->data.exchange(nullptr);
free_external_counter(old_head);
return std::unique_ptr<T>(res);
}
ptr->release_ref();
}
}
}; };
void push(queue<int>* q) void
push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
}
}
void
pop(queue<int>* q)
{
int i = 0;
while (i < 10) {
std::shared_ptr<int> p = q->pop();
if (p) {
printf("poping %d\n", *p);
++i;
} }
}
} }
void pop(queue<int>* q) int
main()
{ {
int i = 0; queue<int> q;
while (i < 10) { std::thread t1(push, &q);
std::shared_ptr<int> p = q->pop(); std::thread t2(pop, &q);
if (p) { t1.join();
printf("poping %d\n", *p); t2.join();
++i; return 0;
}
}
} }
int main()
{
queue<int> q;
std::thread t1(push, &q);
std::thread t2(pop, &q);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,102 +1,98 @@
#include <iostream>
#include <cstdio>
#include <atomic> #include <atomic>
#include <cstdio>
#include <iostream>
#include <memory> #include <memory>
#include <thread> #include <thread>
template <typename T> template <typename T>
class queue class queue {
{ private:
private: struct node {
struct node std::shared_ptr<T> data;
{ node* next;
std::shared_ptr<T> data;
node* next;
node() node() : next(nullptr) {}
: next(nullptr) };
{}
};
std::atomic<node*> head; std::atomic<node*> head;
std::atomic<node*> tail; std::atomic<node*> tail;
node* pop_head() node* pop_head()
{ {
node* const old_head = head.load(); node* const old_head = head.load();
if (old_head == tail.load()) { if (old_head == tail.load()) {
return nullptr; return nullptr;
}
head.store(old_head->next);
return old_head;
} }
public: head.store(old_head->next);
queue() return old_head;
: head(new node) }
, tail(head.load())
{}
queue(const queue& other)=delete; public:
queue& operator=(const queue& other)=delete; queue() : head(new node), tail(head.load()) {}
~queue() queue(const queue& other) = delete;
{ queue& operator=(const queue& other) = delete;
while (node* const old_head = head.load()) {
head.store(old_head->next); ~queue()
delete old_head; {
} while (node* const old_head = head.load()) {
head.store(old_head->next);
delete old_head;
}
}
std::shared_ptr<T> pop()
{
node* old_head = pop_head();
if (!old_head) {
return std::shared_ptr<T>();
} }
std::shared_ptr<T> pop() std::shared_ptr<T> const res(old_head->data);
{ delete old_head;
node* old_head = pop_head(); return res;
if (!old_head) { }
return std::shared_ptr<T>();
}
std::shared_ptr<T> const res(old_head->data); void push(T new_value)
delete old_head; {
return res; std::shared_ptr<T> new_data(std::make_shared<T>(new_value));
} node* p = new node;
node* const old_tail = tail.load();
void push(T new_value) old_tail->data.swap(new_data);
{ old_tail->next = p;
std::shared_ptr<T> new_data(std::make_shared<T>(new_value)); tail.store(p);
node* p = new node; }
node* const old_tail = tail.load();
old_tail->data.swap(new_data);
old_tail->next = p;
tail.store(p);
}
}; };
void push(queue<int>* q) void
push(queue<int>* q)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
q->push(i); q->push(i);
}
}
void
pop(queue<int>* q)
{
int i = 0;
while (i < 10) {
std::shared_ptr<int> p = q->pop();
if (p) {
printf("poping %d\n", *p);
++i;
} }
}
} }
void pop(queue<int>* q) int
main()
{ {
int i = 0; queue<int> q;
while (i < 10) { std::thread t1(push, &q);
std::shared_ptr<int> p = q->pop(); std::thread t2(pop, &q);
if (p) { t1.join();
printf("poping %d\n", *p); t2.join();
++i; return 0;
}
}
} }
int main()
{
queue<int> q;
std::thread t1(push, &q);
std::thread t2(pop, &q);
t1.join();
t2.join();
return 0;
}

View File

@@ -7,168 +7,161 @@
// to_be_deleted list would grow without bounds, and you'd be essentailly // to_be_deleted list would grow without bounds, and you'd be essentailly
// leaking memory again. If there aren't going to be any quiescent periods, // leaking memory again. If there aren't going to be any quiescent periods,
// you need to find an alternative mechanism for reclaming the nodes. The key // you need to find an alternative mechanism for reclaming the nodes. The key
// is to identify when no more threads are accesing a particular node so that // is to identify when no more threads are accesing a particular node so that
// it can reclaimed. By far the easiest such mechanism to reason about is the // it can reclaimed. By far the easiest such mechanism to reason about is the
// use of hazard ponters. // use of hazard ponters.
#include <iostream>
#include <cstdio>
#include <atomic> #include <atomic>
#include <cstdio>
#include <iostream>
#include <memory> #include <memory>
#include <thread> #include <thread>
template <typename T> template <typename T>
class stack class stack {
{ private:
private: struct node {
struct node std::shared_ptr<T> data;
{ node* next;
std::shared_ptr<T> data;
node *next;
node(const T& data_) node(const T& data_) : data(std::make_shared<T>(data_)) {}
: data(std::make_shared<T>(data_)) };
{}
};
std::atomic<node *> head; std::atomic<node*> head;
std::atomic<unsigned> threads_in_pop; std::atomic<unsigned> threads_in_pop;
std::atomic<node *> to_be_deleted; std::atomic<node*> to_be_deleted;
static void delete_nodes(node* nodes)
static void delete_nodes(node *nodes) {
{ while (nodes) {
while (nodes) { node* next = nodes->next;
node *next = nodes->next; delete nodes;
delete nodes; nodes = next;
nodes = next;
}
} }
}
void try_reclaim(node* old_head) void try_reclaim(node* old_head)
{ {
if (threads_in_pop == 1) { if (threads_in_pop == 1) {
// claim list of to-be-deleted nodes // claim list of to-be-deleted nodes
node* nodes_to_delete = to_be_deleted.exchange(nullptr); node* nodes_to_delete = to_be_deleted.exchange(nullptr);
// are you the only thread in pop()? // are you the only thread in pop()?
if (!--threads_in_pop) { if (!--threads_in_pop) {
// on other thread can be accessing this list of pending nodes. // on other thread can be accessing this list of pending nodes.
// There may be new pending nodes, but you're not bothered // There may be new pending nodes, but you're not bothered
// about them for now, as long as it's safe to reclaim your // about them for now, as long as it's safe to reclaim your
// list. // list.
delete_nodes(nodes_to_delete); delete_nodes(nodes_to_delete);
} }
else if (nodes_to_delete) { else if (nodes_to_delete) {
// not safe to reclaim the nodes, so if there are any, // not safe to reclaim the nodes, so if there are any,
// you must chain them back onto the list of nodes // you must chain them back onto the list of nodes
// pending deletion. // pending deletion.
// This can happen if there are multiple threads accessing the // This can happen if there are multiple threads accessing the
// data structure concurrently. Other threads might have // data structure concurrently. Other threads might have
// called pop() in between the first tet of thread_in_pop and // called pop() in between the first tet of thread_in_pop and
// the "claiming" of the list, potentially adding new nodes to // the "claiming" of the list, potentially adding new nodes to
// the list that are still being accesed by one or more of // the list that are still being accesed by one or more of
// those other threads. // those other threads.
chain_pending_nodes(nodes_to_delete); chain_pending_nodes(nodes_to_delete);
} }
delete old_head; delete old_head;
}
else {
// not safe to delete any nodes, add the node to the pending list
chain_pending_node(old_head);
--threads_in_pop;
}
} }
else {
void chain_pending_nodes(node* nodes) // not safe to delete any nodes, add the node to the pending list
{ chain_pending_node(old_head);
node* last = nodes; --threads_in_pop;
// traverse the chain to find the end
while (node* const next = last->next) {
last = next;
}
chain_pending_nodes(nodes, last);
} }
}
void chain_pending_nodes(node* first, node* last) void chain_pending_nodes(node* nodes)
{ {
// replace the next pointer from the last node with node* last = nodes;
// the current to_be_deleted pointer // traverse the chain to find the end
last->next = to_be_deleted; while (node* const next = last->next) {
// store the first node in the chain as the new to_be_deleted pointer last = next;
// have to use compare_exchange_weak in a loop here in order to ensure
// that you don't leak any nodes that have been added by another thread
while (!to_be_deleted.compare_exchange_weak(
last->next,first));
} }
chain_pending_nodes(nodes, last);
}
void chain_pending_node(node* n) void chain_pending_nodes(node* first, node* last)
{ {
// adding a single node onto the list is a special case where the // replace the next pointer from the last node with
// first node onto the list is a special case where the first node // the current to_be_deleted pointer
// in the chain to be added is the same as the last one. last->next = to_be_deleted;
chain_pending_nodes(n,n); // store the first node in the chain as the new to_be_deleted pointer
} // have to use compare_exchange_weak in a loop here in order to ensure
// that you don't leak any nodes that have been added by another thread
public: while (!to_be_deleted.compare_exchange_weak(last->next, first))
stack() ;
: head(nullptr) }
, threads_in_pop(0)
, to_be_deleted(nullptr) void chain_pending_node(node* n)
{} {
// adding a single node onto the list is a special case where the
void push(const T& data) // first node onto the list is a special case where the first node
{ // in the chain to be added is the same as the last one.
node *const new_node = new node(data); chain_pending_nodes(n, n);
new_node->next = head.load(); }
// loop to gurantee that last->next is correct
while (!head.compare_exchange_weak(new_node->next, new_node)); public:
} stack() : head(nullptr), threads_in_pop(0), to_be_deleted(nullptr) {}
std::shared_ptr<T> pop() void push(const T& data)
{ {
++threads_in_pop; // increase counter before doing anything else node* const new_node = new node(data);
node *old_head = head.load(); new_node->next = head.load();
while (old_head && // loop to gurantee that last->next is correct
!head.compare_exchange_weak(old_head, old_head->next)); while (!head.compare_exchange_weak(new_node->next, new_node))
std::shared_ptr<T> res; ;
if (old_head) { }
res.swap(old_head->data); // extract data from node rather than
// coping pointer std::shared_ptr<T> pop()
} {
try_reclaim(old_head); // reclaim deleted nodes if you can ++threads_in_pop; // increase counter before doing anything else
return res; node* old_head = head.load();
while (old_head && !head.compare_exchange_weak(old_head, old_head->next))
;
std::shared_ptr<T> res;
if (old_head) {
res.swap(old_head->data); // extract data from node rather than
// coping pointer
} }
try_reclaim(old_head); // reclaim deleted nodes if you can
return res;
}
}; };
void push(stack<int>* s) void
push(stack<int>* s)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
s->push(i); s->push(i);
}
}
void
pop(stack<int>* s)
{
int count = 0;
std::shared_ptr<int> e;
while (count < 10) {
if (e = s->pop()) {
printf("popping %d\n", *e);
++count;
} }
}
} }
void pop(stack<int>* s) int
main()
{ {
int count = 0; stack<int> s;
std::shared_ptr<int> e; std::thread t1(push, &s);
while (count < 10) { std::thread t2(pop, &s);
if (e = s->pop()) { t1.join();
printf("popping %d\n", *e); t2.join();
++count; return 0;
}
}
} }
int main()
{
stack<int> s;
std::thread t1(push, &s);
std::thread t2(pop, &s);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,193 +1,191 @@
#include <iostream>
#include <cstdio>
#include <atomic> #include <atomic>
#include <cstdio>
#include <iostream>
#include <memory> #include <memory>
#include <thread> #include <thread>
#include "hazard_pointer.h" #include "hazard_pointer.h"
std::atomic<void*>& get_hazard_pointer_for_current_thread() std::atomic<void*>&
get_hazard_pointer_for_current_thread()
{ {
// The first time each thread calls this function, a new instance of // The first time each thread calls this function, a new instance of
// hp_owner is created. The constructor for this new instance then // hp_owner is created. The constructor for this new instance then
// searchs through the table of owner/pointer pairs looking for an entry // searchs through the table of owner/pointer pairs looking for an entry
// without an owner. It uses compare_exchange_strong() to check for an // without an owner. It uses compare_exchange_strong() to check for an
// entry without an owner and claim it in one go. // entry without an owner and claim it in one go.
// //
// Once the hp_owner instance has been created for a given thread, further // Once the hp_owner instance has been created for a given thread, further
// accesses are much faster because the pointer is cached, so the table // accesses are much faster because the pointer is cached, so the table
// doesn't have to be scanned again. // doesn't have to be scanned again.
printf("get harzard pointer for current thread, thread id: %d\n", std::this_thread::get_id()); printf("get harzard pointer for current thread, thread id: %d\n",
thread_local static hp_owner hazard; std::this_thread::get_id());
return hazard.get_pointer(); thread_local static hp_owner hazard;
return hazard.get_pointer();
} }
bool outstanding_hazard_pointers_for(void *p) bool
outstanding_hazard_pointers_for(void* p)
{ {
for (unsigned i = 0; i < max_hazard_pointers; ++i) { for (unsigned i = 0; i < max_hazard_pointers; ++i) {
if (hazard_pointers[i].pointer.load() == p) { if (hazard_pointers[i].pointer.load() == p) {
return true; return true;
}
} }
return false; }
return false;
} }
template <typename T> template <typename T>
void do_delete(void* p) void
do_delete(void* p)
{ {
delete static_cast<T*>(p); delete static_cast<T*>(p);
} }
struct data_to_reclaim struct data_to_reclaim {
{ void* data;
void* data; std::function<void(void*)> deleter;
std::function<void(void *)> deleter; data_to_reclaim* next;
data_to_reclaim* next;
template<typename T> template <typename T>
data_to_reclaim(T* p) data_to_reclaim(T* p) : data(p), deleter(&do_delete<T>), next(0)
: data(p) {
, deleter(&do_delete<T>) }
, next(0)
{}
~data_to_reclaim() ~data_to_reclaim() { deleter(data); }
{
deleter(data);
}
}; };
std::atomic<data_to_reclaim*> nodes_to_reclaim; std::atomic<data_to_reclaim*> nodes_to_reclaim;
void add_to_reclaim_list(data_to_reclaim* node) void
add_to_reclaim_list(data_to_reclaim* node)
{ {
node->next = nodes_to_reclaim.load(); node->next = nodes_to_reclaim.load();
while (!nodes_to_reclaim.compare_exchange_weak(node->next, node)); while (!nodes_to_reclaim.compare_exchange_weak(node->next, node))
} ;
template<typename T>
void reclaim_later(T* data)
{
add_to_reclaim_list(new data_to_reclaim(data));
}
void delete_nodes_with_no_hazards()
{
// first claims the entire list of nodes to be reclaimed;
// ensures that this is the only thread trying to reclaim
// this particular set of nodes; other threads are now free
// to add futher nodes to the list or event try to reclaim
// them without impacting the operation of this thread.
data_to_reclaim* current = nodes_to_reclaim.exchange(nullptr);
while (current) {
data_to_reclaim* const next = current->next;
// check each node in turn to see if there are any outstanding
// hazard pointers.
if (!outstanding_hazard_pointers_for(current->data)) {
// if there aren't, delete the entry
delete current;
}
else {
// otherwise, just add the item back on the list for
// reclaiming later
add_to_reclaim_list(current);
}
current=next;
}
} }
template <typename T> template <typename T>
class stack void
reclaim_later(T* data)
{ {
private: add_to_reclaim_list(new data_to_reclaim(data));
struct node }
{
std::shared_ptr<T> data;
node *next;
node(const T& data_) void
: data(std::make_shared<T>(data_)) delete_nodes_with_no_hazards()
{} {
}; // first claims the entire list of nodes to be reclaimed;
// ensures that this is the only thread trying to reclaim
// this particular set of nodes; other threads are now free
// to add futher nodes to the list or event try to reclaim
// them without impacting the operation of this thread.
data_to_reclaim* current = nodes_to_reclaim.exchange(nullptr);
std::atomic<node *> head; while (current) {
data_to_reclaim* const next = current->next;
public: // check each node in turn to see if there are any outstanding
stack() // hazard pointers.
: head(nullptr) if (!outstanding_hazard_pointers_for(current->data)) {
{} // if there aren't, delete the entry
delete current;
void push(const T& data)
{
node *const new_node = new node(data);
new_node->next = head.load();
while (!head.compare_exchange_weak(new_node->next, new_node));
} }
else {
std::shared_ptr<T> pop() // otherwise, just add the item back on the list for
{ // reclaiming later
std::atomic<void*>& hp = get_hazard_pointer_for_current_thread(); add_to_reclaim_list(current);
node* old_head = head.load();
do {
node* temp;
do { // loop until you've set the harzard pointer to head
temp = old_head;
hp.store(old_head);
old_head = head.load();
} while (old_head != temp);
}
while (old_head &&
!head.compare_exchange_strong(old_head, old_head->next));
hp.store(nullptr); // clear hazard pointer once you're finished
std::shared_ptr<T> res;
if (old_head) {
res.swap(old_head->data);
if (outstanding_hazard_pointers_for(old_head)) {
// check for hazard pointers referencing
// a node before you delete it
reclaim_later(old_head);
}
else {
delete old_head;
}
delete_nodes_with_no_hazards();
}
return res;
} }
current = next;
}
}
template <typename T>
class stack {
private:
struct node {
std::shared_ptr<T> data;
node* next;
node(const T& data_) : data(std::make_shared<T>(data_)) {}
};
std::atomic<node*> head;
public:
stack() : head(nullptr) {}
void push(const T& data)
{
node* const new_node = new node(data);
new_node->next = head.load();
while (!head.compare_exchange_weak(new_node->next, new_node))
;
}
std::shared_ptr<T> pop()
{
std::atomic<void*>& hp = get_hazard_pointer_for_current_thread();
node* old_head = head.load();
do {
node* temp;
do { // loop until you've set the harzard pointer to head
temp = old_head;
hp.store(old_head);
old_head = head.load();
} while (old_head != temp);
} while (old_head &&
!head.compare_exchange_strong(old_head, old_head->next));
hp.store(nullptr); // clear hazard pointer once you're finished
std::shared_ptr<T> res;
if (old_head) {
res.swap(old_head->data);
if (outstanding_hazard_pointers_for(old_head)) {
// check for hazard pointers referencing
// a node before you delete it
reclaim_later(old_head);
}
else {
delete old_head;
}
delete_nodes_with_no_hazards();
}
return res;
}
}; };
void push(stack<int>* s) void
push(stack<int>* s)
{ {
printf("starting push\n"); printf("starting push\n");
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
s->push(i); s->push(i);
}
}
void
pop(stack<int>* s)
{
printf("starting pop\n");
int count = 0;
std::shared_ptr<int> e;
while (count < 10) {
if (e = s->pop()) {
printf("popping %d\n", *e);
++count;
} }
}
} }
void pop(stack<int>* s) int
main()
{ {
printf("starting pop\n"); printf("creating stack\n");
int count = 0; stack<int> s;
std::shared_ptr<int> e; printf("stack created\n");
while (count < 10) { std::thread t1(push, &s);
if (e = s->pop()) { std::thread t2(pop, &s);
printf("popping %d\n", *e); t1.join();
++count; t2.join();
} return 0;
}
} }
int main()
{
printf("creating stack\n");
stack<int> s;
printf("stack created\n");
std::thread t1(push, &s);
std::thread t2(pop, &s);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,183 +1,171 @@
#include <iostream>
#include <cstdio>
#include <atomic> #include <atomic>
#include <cstdio>
#include <iostream>
#include <memory> #include <memory>
#include <thread> #include <thread>
template <typename T> template <typename T>
class stack class stack {
{ private:
private: struct node;
struct node;
// the external count is kept alongside the poiner to the node and is
// increased every time the pointer is read. When the reader is finished
// with the node, it decraes the internal count. A simple operation that
// reads the pointer will thus leave the external count increaesd by one
// and the internal count decreased by one when it's finished.
//
// When the external count/pointer pairing is no longer required (that is,
// the node is no longer accessbile from a location accessible to multple
// threads), the internal count is increased by the value of the external
// count minus one and external counter is discarded. Once the internal
// count is equal to zero, there are no outstanding references to the node
// and it can be safely deleted.
struct counted_node_ptr
{
int external_count;
node *ptr;
};
struct node // the external count is kept alongside the poiner to the node and is
{ // increased every time the pointer is read. When the reader is finished
std::shared_ptr<T> data; // with the node, it decraes the internal count. A simple operation that
std::atomic_int internal_count; // reads the pointer will thus leave the external count increaesd by one
counted_node_ptr next; // and the internal count decreased by one when it's finished.
//
// When the external count/pointer pairing is no longer required (that is,
// the node is no longer accessbile from a location accessible to multple
// threads), the internal count is increased by the value of the external
// count minus one and external counter is discarded. Once the internal
// count is equal to zero, there are no outstanding references to the node
// and it can be safely deleted.
struct counted_node_ptr {
int external_count;
node* ptr;
};
node(const T& data_) struct node {
: data(new T(data_)) std::shared_ptr<T> data;
, internal_count(0) std::atomic_int internal_count;
{} counted_node_ptr next;
};
std::atomic<counted_node_ptr> head; node(const T& data_) : data(new T(data_)), internal_count(0) {}
// NOTE: on those platforms that support a double-word-compare-and-swap };
// operation, counted_node_ptr will be small enough for
// std::atomic<counted_node_ptr> to be lock-free. If it isn't on your
// platform, you might be better off using the std::shared_ptr<> version,
// because std::atomic<> will use a mutex to guarantee atomicity when the
// type is too large for the pltaform's atomic instrcutions (thus rending
// your "lock-free" algorithm lock-based after all). Alternatively, if
// you are're willing to limit the size of the counter, and you know that
// your platform has spare bits in a pointer (for example, because the
// address space is only 48 bits but a pointer is 64 bits), you can store
// the count inside the spare bits of the pointer to fit it all back in a
// single machine word.
std::atomic<counted_node_ptr> head;
// NOTE: on those platforms that support a double-word-compare-and-swap
// operation, counted_node_ptr will be small enough for
// std::atomic<counted_node_ptr> to be lock-free. If it isn't on your
// platform, you might be better off using the std::shared_ptr<> version,
// because std::atomic<> will use a mutex to guarantee atomicity when the
// type is too large for the pltaform's atomic instrcutions (thus rending
// your "lock-free" algorithm lock-based after all). Alternatively, if
// you are're willing to limit the size of the counter, and you know that
// your platform has spare bits in a pointer (for example, because the
// address space is only 48 bits but a pointer is 64 bits), you can store
// the count inside the spare bits of the pointer to fit it all back in a
// single machine word.
// once you've loaded the value of head, you must first increaes the count // once you've loaded the value of head, you must first increaes the count
// of external references to the head node to indicate that you're // of external references to the head node to indicate that you're
// referencing it and to ensure that it's safe to deference it. // referencing it and to ensure that it's safe to deference it.
// By incrementing the external reference count, you ensure that the // By incrementing the external reference count, you ensure that the
// pointer remains valid for the duration of your access. // pointer remains valid for the duration of your access.
void increase_head_count(counted_node_ptr& old_counter) void increase_head_count(counted_node_ptr& old_counter)
{ {
counted_node_ptr new_counter; counted_node_ptr new_counter;
do do {
{ new_counter = old_counter;
new_counter = old_counter; ++new_counter.external_count;
++new_counter.external_count; } while (!head.compare_exchange_strong(old_counter, new_counter));
old_counter.external_count = new_counter.external_count;
}
public:
~stack()
{
while (pop())
;
}
void push(const T& data)
{
counted_node_ptr new_node;
new_node.ptr = new node(data);
// internal_count is zeor, and the external_count is one;
// because this is a new node, there's currently only one
// external reference to the node (the head pointer itself).
new_node.external_count = 1;
new_node.ptr->next = head.load();
while (!head.compare_exchange_weak(new_node.ptr->next, new_node))
;
}
std::shared_ptr<T> pop()
{
counted_node_ptr old_head = head.load();
for (;;) {
increase_head_count(old_head);
node* ptr = old_head.ptr;
// if the pointer is a null pointer, you're at the end of list:
// no more entires
if (!ptr) {
return std::shared_ptr<T>();
}
// if the pointer isn't a null pointer, try to remove the node
if (head.compare_exchange_strong(old_head, ptr->next)) {
// you've taken the ownership of the node and can swap out
// the data in prepration for returning it.
std::shared_ptr<T> res;
res.swap(ptr->data);
// you've removed the node from the list, so you drop one
// off the count for that, and you're no longer accessing
// the node from this thread, so you drop another off the
// count for that.
const int count_increase = old_head.external_count - 2;
// if the reference count is now zero, the previous value
// (which is what fetch_add returns) was the negative of what
// you just added, in which case you can delete the node.
if (ptr->internal_count.fetch_add(count_increase) == -count_increase) {
delete ptr;
} }
while (!head.compare_exchange_strong(old_counter, new_counter));
old_counter.external_count = new_counter.external_count; // whether or not you deleted the node, you've finished.
} return res;
}
public: // if the compare/exchange fails, another therad removed your node
~stack() // before you did, or another thread added a new node to the stack.
{ // Either way, you need start again with the fresh value of head
while (pop()); // returned by the compare/exchange call. But first you must
} // decrease the reference count on the node you were trying to
// remove. This thread won't access it anymore. If you're the last
void push(const T& data) // thread to hold a reference (because another thread removed it
{ // from the stack), the internal reference count will be 1, so
counted_node_ptr new_node; // subtracing 1 will set the count to zero. In this case, you can
new_node.ptr = new node(data); // delete the node here before you loop.
// internal_count is zeor, and the external_count is one; else if (ptr->internal_count.fetch_add(-1) == 1) {
// because this is a new node, there's currently only one delete ptr;
// external reference to the node (the head pointer itself). }
new_node.external_count = 1;
new_node.ptr->next = head.load();
while (!head.compare_exchange_weak(new_node.ptr->next, new_node));
}
std::shared_ptr<T> pop()
{
counted_node_ptr old_head = head.load();
for (;;)
{
increase_head_count(old_head);
node* ptr = old_head.ptr;
// if the pointer is a null pointer, you're at the end of list:
// no more entires
if (!ptr)
{
return std::shared_ptr<T>();
}
// if the pointer isn't a null pointer, try to remove the node
if (head.compare_exchange_strong(old_head,ptr->next))
{
// you've taken the ownership of the node and can swap out
// the data in prepration for returning it.
std::shared_ptr<T> res;
res.swap(ptr->data);
// you've removed the node from the list, so you drop one
// off the count for that, and you're no longer accessing
// the node from this thread, so you drop another off the
// count for that.
const int count_increase = old_head.external_count - 2;
// if the reference count is now zero, the previous value
// (which is what fetch_add returns) was the negative of what
// you just added, in which case you can delete the node.
if (ptr->internal_count.fetch_add(count_increase) ==
-count_increase)
{
delete ptr;
}
// whether or not you deleted the node, you've finished.
return res;
}
// if the compare/exchange fails, another therad removed your node
// before you did, or another thread added a new node to the stack.
// Either way, you need start again with the fresh value of head
// returned by the compare/exchange call. But first you must
// decrease the reference count on the node you were trying to
// remove. This thread won't access it anymore. If you're the last
// thread to hold a reference (because another thread removed it
// from the stack), the internal reference count will be 1, so
// subtracing 1 will set the count to zero. In this case, you can
// delete the node here before you loop.
else if (ptr->internal_count.fetch_add(-1) == 1)
{
delete ptr;
}
}
} }
}
}; };
void push(stack<int>* s) void
push(stack<int>* s)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
s->push(i); s->push(i);
}
}
void
pop(stack<int>* s)
{
int count = 0;
std::shared_ptr<int> e;
while (count < 10) {
if (e = s->pop()) {
printf("popping %d\n", *e);
++count;
} }
}
} }
void pop(stack<int>* s) int
main()
{ {
int count = 0; stack<int> s;
std::shared_ptr<int> e; std::thread t1(push, &s);
while (count < 10) { std::thread t2(pop, &s);
if (e = s->pop()) { t1.join();
printf("popping %d\n", *e); t2.join();
++count; return 0;
}
}
} }
int main()
{
stack<int> s;
std::thread t1(push, &s);
std::thread t2(pop, &s);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,70 +1,70 @@
#include <thread>
#include <memory>
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include <memory>
#include <thread>
template <typename T> template <typename T>
class stack class stack {
{ private:
private: struct node {
struct node std::shared_ptr<T> data;
{ std::shared_ptr<node> next;
std::shared_ptr<T> data;
std::shared_ptr<node> next;
node(T const& data_) node(T const& data_) : data(std::make_shared<T>(data_)) {}
: data(std::make_shared<T>(data_)) };
{}
};
std::shared_ptr<node> head; std::shared_ptr<node> head;
public:
void push(T const& data) public:
{ void push(T const& data)
std::shared_ptr<node> const new_node = std::make_shared<node>(data); {
new_node->next = std::atomic_load(head); std::shared_ptr<node> const new_node = std::make_shared<node>(data);
while (!std::atomic_compare_exchange_weak(&head, new_node->next = std::atomic_load(head);
&new_node->next, new_node)); while (!std::atomic_compare_exchange_weak(&head, &new_node->next, new_node))
} ;
std::shared_ptr<T> pop() }
{ std::shared_ptr<T> pop()
std::shared_ptr<node> old_head = std::atomic_load(head); {
while (old_head && !std::atomic_compare_exchange_weak(&head, std::shared_ptr<node> old_head = std::atomic_load(head);
&old_head, old_head->next)); while (old_head &&
return old_head ? old_head->data : std::shared_ptr<T>(); !std::atomic_compare_exchange_weak(&head, &old_head, old_head->next))
} ;
return old_head ? old_head->data : std::shared_ptr<T>();
}
}; };
void push(stack<int>* s) void
push(stack<int>* s)
{ {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
printf("pushing %d\n", i); printf("pushing %d\n", i);
s->push(i); s->push(i);
}
}
void
pop(stack<int>* s)
{
int count = 0;
std::shared_ptr<int> e;
while (count < 10) {
if (e = s->pop()) {
printf("popping %d\n", *e);
++count;
} }
}
} }
void pop(stack<int>* s) int
main()
{ {
int count = 0; std::shared_ptr<int> sp = std::make_shared<int>(1);
std::shared_ptr<int> e; // printf("std::atomic_is_lock_free(std::shared_ptr): %d\n",
while (count < 10) { // std::atomic_is_lock_free(&sp));
if (e = s->pop()) { stack<int> s;
printf("popping %d\n", *e); std::thread t1(push, &s);
++count; std::thread t2(pop, &s);
} t1.join();
} t2.join();
return 0;
} }
int main()
{
std::shared_ptr<int> sp = std::make_shared<int>(1);
//printf("std::atomic_is_lock_free(std::shared_ptr): %d\n",
// std::atomic_is_lock_free(&sp));
stack<int> s;
std::thread t1(push, &s);
std::thread t2(pop, &s);
t1.join();
t2.join();
return 0;
}

View File

@@ -1,13 +1,15 @@
#include <iostream> #include <iostream>
#include <thread> #include <thread>
void hello() void
hello()
{ {
std::cout<<"Hello Concurrent World\n"; std::cout << "Hello Concurrent World\n";
} }
int main() int
main()
{ {
std::thread t(hello); std::thread t(hello);
t.join(); t.join();
} }

View File

@@ -1,42 +1,35 @@
void test_concurrent_push_and_pop_on_empty_queue() void
test_concurrent_push_and_pop_on_empty_queue()
{ {
threadsafe_queue<int> q; threadsafe_queue<int> q;
std::promise<void> go,push_ready,pop_ready; std::promise<void> go, push_ready, pop_ready;
std::shared_future<void> ready(go.get_future()); std::shared_future<void> ready(go.get_future());
std::future<void> push_done; std::future<void> push_done;
std::future<int> pop_done; std::future<int> pop_done;
try try {
{ push_done = std::async(std::launch::async, [&q, ready, &push_ready]() {
push_done=std::async(std::launch::async, push_ready.set_value();
[&q,ready,&push_ready]() ready.wait();
{ q.push(42);
push_ready.set_value(); });
ready.wait(); pop_done = std::async(std::launch::async, [&q, ready, &pop_ready]() {
q.push(42); pop_ready.set_value();
} ready.wait();
); return q.pop();
pop_done=std::async(std::launch::async, });
[&q,ready,&pop_ready]() push_ready.get_future().wait();
{ pop_ready.get_future().wait();
pop_ready.set_value(); go.set_value();
ready.wait();
return q.pop();
}
);
push_ready.get_future().wait();
pop_ready.get_future().wait();
go.set_value();
push_done.get(); push_done.get();
assert(pop_done.get()==42); assert(pop_done.get() == 42);
assert(q.empty()); assert(q.empty());
} }
catch(...) catch (...) {
{ go.set_value();
go.set_value(); throw;
throw; }
}
} }

View File

@@ -1,35 +1,35 @@
#include <thread> #include <thread>
void do_something(int& i) void
do_something(int& i)
{ {
++i; ++i;
} }
struct func struct func {
{ int& i;
int& i;
func(int& i_):i(i_){} func(int& i_) : i(i_) {}
void operator()() void operator()()
{ {
for(unsigned j=0;j<1000000;++j) for (unsigned j = 0; j < 1000000; ++j) {
{ do_something(i);
do_something(i);
}
} }
}
}; };
void
void oops() oops()
{ {
int some_local_state=0; int some_local_state = 0;
func my_func(some_local_state); func my_func(some_local_state);
std::thread my_thread(my_func); std::thread my_thread(my_func);
my_thread.detach(); my_thread.detach();
} }
int main() int
main()
{ {
oops(); oops();
} }

View File

@@ -1,46 +1,47 @@
#include <thread> #include <thread>
void do_something(int& i) void
do_something(int& i)
{ {
++i; ++i;
} }
struct func struct func {
{ int& i;
int& i;
func(int& i_):i(i_){} func(int& i_) : i(i_) {}
void operator()() void operator()()
{ {
for(unsigned j=0;j<1000000;++j) for (unsigned j = 0; j < 1000000; ++j) {
{ do_something(i);
do_something(i);
}
} }
}
}; };
void do_something_in_current_thread() void
{} do_something_in_current_thread()
void f()
{ {
int some_local_state=0; }
func my_func(some_local_state);
std::thread t(my_func); void
try f()
{ {
do_something_in_current_thread(); int some_local_state = 0;
} func my_func(some_local_state);
catch(...) std::thread t(my_func);
{ try {
t.join(); do_something_in_current_thread();
throw; }
} catch (...) {
t.join(); t.join();
throw;
}
t.join();
} }
int main() int
main()
{ {
f(); f();
} }

View File

@@ -1,58 +1,57 @@
#include <thread> #include <thread>
class thread_guard class thread_guard {
{ std::thread& t;
std::thread& t;
public: public:
explicit thread_guard(std::thread& t_): explicit thread_guard(std::thread& t_) : t(t_) {}
t(t_) ~thread_guard()
{} {
~thread_guard() if (t.joinable()) {
{ t.join();
if(t.joinable())
{
t.join();
}
} }
thread_guard(thread_guard const&)=delete; }
thread_guard& operator=(thread_guard const&)=delete; thread_guard(thread_guard const&) = delete;
thread_guard& operator=(thread_guard const&) = delete;
}; };
void do_something(int& i) void
do_something(int& i)
{ {
++i; ++i;
} }
struct func struct func {
{ int& i;
int& i;
func(int& i_):i(i_){} func(int& i_) : i(i_) {}
void operator()() void operator()()
{ {
for(unsigned j=0;j<1000000;++j) for (unsigned j = 0; j < 1000000; ++j) {
{ do_something(i);
do_something(i);
}
} }
}
}; };
void do_something_in_current_thread() void
{} do_something_in_current_thread()
void f()
{ {
int some_local_state;
func my_func(some_local_state);
std::thread t(my_func);
thread_guard g(t);
do_something_in_current_thread();
} }
int main() void
f()
{ {
f(); int some_local_state;
func my_func(some_local_state);
std::thread t(my_func);
thread_guard g(t);
do_something_in_current_thread();
}
int
main()
{
f();
} }

View File

@@ -1,61 +1,61 @@
#include <thread>
#include <string> #include <string>
#include <thread>
void open_document_and_display_gui(std::string const& filename) void
{} open_document_and_display_gui(std::string const& filename)
bool done_editing()
{ {
return true;
} }
enum command_type{ bool
open_new_document done_editing()
{
return true;
}
enum command_type { open_new_document };
struct user_command {
command_type type;
user_command() : type(open_new_document) {}
}; };
user_command
struct user_command get_user_input()
{ {
command_type type; return user_command();
user_command():
type(open_new_document)
{}
};
user_command get_user_input()
{
return user_command();
} }
std::string get_filename_from_user() std::string
get_filename_from_user()
{ {
return "foo.doc"; return "foo.doc";
} }
void process_user_input(user_command const& cmd) void
{} process_user_input(user_command const& cmd)
void edit_document(std::string const& filename)
{ {
open_document_and_display_gui(filename); }
while(!done_editing())
{ void
user_command cmd=get_user_input(); edit_document(std::string const& filename)
if(cmd.type==open_new_document) {
{ open_document_and_display_gui(filename);
std::string const new_name=get_filename_from_user(); while (!done_editing()) {
std::thread t(edit_document,new_name); user_command cmd = get_user_input();
t.detach(); if (cmd.type == open_new_document) {
} std::string const new_name = get_filename_from_user();
else std::thread t(edit_document, new_name);
{ t.detach();
process_user_input(cmd);
}
} }
else {
process_user_input(cmd);
}
}
} }
int main() int
main()
{ {
edit_document("bar.doc"); edit_document("bar.doc");
} }

View File

@@ -1,27 +1,34 @@
#include <thread> #include <thread>
void some_function() void
{} some_function()
void some_other_function(int)
{}
std::thread f()
{ {
void some_function();
return std::thread(some_function);
}
std::thread g()
{
void some_other_function(int);
std::thread t(some_other_function,42);
return t;
} }
int main() void
some_other_function(int)
{ {
std::thread t1=f(); }
t1.join();
std::thread t2=g(); std::thread
t2.join(); f()
{
void some_function();
return std::thread(some_function);
}
std::thread
g()
{
void some_other_function(int);
std::thread t(some_other_function, 42);
return t;
}
int
main()
{
std::thread t1 = f();
t1.join();
std::thread t2 = g();
t2.join();
} }

View File

@@ -1,56 +1,55 @@
#include <thread> #include <thread>
#include <utility> #include <utility>
class scoped_thread class scoped_thread {
{ std::thread t;
std::thread t;
public: public:
explicit scoped_thread(std::thread t_): explicit scoped_thread(std::thread t_) : t(std::move(t_))
t(std::move(t_)) {
{ if (!t.joinable())
if(!t.joinable()) throw std::logic_error("No thread");
throw std::logic_error("No thread"); }
} ~scoped_thread() { t.join(); }
~scoped_thread() scoped_thread(scoped_thread const&) = delete;
{ scoped_thread& operator=(scoped_thread const&) = delete;
t.join();
}
scoped_thread(scoped_thread const&)=delete;
scoped_thread& operator=(scoped_thread const&)=delete;
}; };
void do_something(int& i) void
do_something(int& i)
{ {
++i; ++i;
} }
struct func struct func {
{ int& i;
int& i;
func(int& i_):i(i_){} func(int& i_) : i(i_) {}
void operator()() void operator()()
{ {
for(unsigned j=0;j<1000000;++j) for (unsigned j = 0; j < 1000000; ++j) {
{ do_something(i);
do_something(i);
}
} }
}
}; };
void do_something_in_current_thread() void
{} do_something_in_current_thread()
void f()
{ {
int some_local_state;
scoped_thread t(std::thread(func(some_local_state)));
do_something_in_current_thread();
} }
int main() void
f()
{ {
f(); int some_local_state;
scoped_thread t(std::thread(func(some_local_state)));
do_something_in_current_thread();
}
int
main()
{
f();
} }

View File

@@ -1,23 +1,26 @@
#include <vector>
#include <thread>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <thread>
#include <vector>
void do_work(unsigned id) void
{} do_work(unsigned id)
void f()
{ {
std::vector<std::thread> threads;
for(unsigned i=0;i<20;++i)
{
threads.push_back(std::thread(do_work,i));
}
std::for_each(threads.begin(),threads.end(),
std::mem_fn(&std::thread::join));
} }
int main() void
f()
{ {
f(); std::vector<std::thread> threads;
for (unsigned i = 0; i < 20; ++i) {
threads.push_back(std::thread(do_work, i));
}
std::for_each(
threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
}
int
main()
{
f();
} }

View File

@@ -1,67 +1,66 @@
#include <thread>
#include <numeric>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <vector>
#include <iostream> #include <iostream>
#include <numeric>
#include <thread>
#include <vector>
template<typename Iterator,typename T> template <typename Iterator, typename T>
struct accumulate_block struct accumulate_block {
{ void operator()(Iterator first, Iterator last, T& result)
void operator()(Iterator first,Iterator last,T& result) {
{ result = std::accumulate(first, last, result);
result=std::accumulate(first,last,result); }
}
}; };
template<typename Iterator,typename T> template <typename Iterator, typename T>
T parallel_accumulate(Iterator first,Iterator last,T init) T
parallel_accumulate(Iterator first, Iterator last, T init)
{ {
unsigned long const length=std::distance(first,last); unsigned long const length = std::distance(first, last);
if(!length) if (!length)
return init; return init;
unsigned long const min_per_thread=25; unsigned long const min_per_thread = 25;
unsigned long const max_threads= unsigned long const max_threads =
(length+min_per_thread-1)/min_per_thread; (length + min_per_thread - 1) / min_per_thread;
unsigned long const hardware_threads= unsigned long const hardware_threads = std::thread::hardware_concurrency();
std::thread::hardware_concurrency();
unsigned long const num_threads= unsigned long const num_threads =
std::min(hardware_threads!=0?hardware_threads:2,max_threads); std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads);
unsigned long const block_size=length/num_threads; unsigned long const block_size = length / num_threads;
std::vector<T> results(num_threads); std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_threads-1); std::vector<std::thread> threads(num_threads - 1);
Iterator block_start=first; Iterator block_start = first;
for(unsigned long i=0;i<(num_threads-1);++i) for (unsigned long i = 0; i < (num_threads - 1); ++i) {
{ Iterator block_end = block_start;
Iterator block_end=block_start; std::advance(block_end, block_size);
std::advance(block_end,block_size); threads[i] = std::thread(accumulate_block<Iterator, T>(),
threads[i]=std::thread( block_start,
accumulate_block<Iterator,T>(), block_end,
block_start,block_end,std::ref(results[i])); std::ref(results[i]));
block_start=block_end; block_start = block_end;
} }
accumulate_block<Iterator,T>()(block_start,last,results[num_threads-1]); accumulate_block<Iterator, T>()(block_start, last, results[num_threads - 1]);
std::for_each(threads.begin(),threads.end(),
std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(),results.end(),init); std::for_each(
threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(), results.end(), init);
} }
int main() int
main()
{ {
std::vector<int> vi; std::vector<int> vi;
for(int i=0;i<10;++i) for (int i = 0; i < 10; ++i) {
{ vi.push_back(10);
vi.push_back(10); }
} int sum = parallel_accumulate(vi.begin(), vi.end(), 5);
int sum=parallel_accumulate(vi.begin(),vi.end(),5); std::cout << "sum=" << sum << std::endl;
std::cout<<"sum="<<sum<<std::endl;
} }

View File

@@ -1,26 +1,30 @@
#include <algorithm>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <algorithm>
std::list<int> some_list; std::list<int> some_list;
std::mutex some_mutex; std::mutex some_mutex;
void add_to_list(int new_value) void
add_to_list(int new_value)
{ {
std::lock_guard<std::mutex> guard(some_mutex); std::lock_guard<std::mutex> guard(some_mutex);
some_list.push_back(new_value); some_list.push_back(new_value);
} }
bool list_contains(int value_to_find) bool
list_contains(int value_to_find)
{ {
std::lock_guard<std::mutex> guard(some_mutex); std::lock_guard<std::mutex> guard(some_mutex);
return std::find(some_list.begin(),some_list.end(),value_to_find) return std::find(some_list.begin(), some_list.end(), value_to_find) !=
!= some_list.end(); some_list.end();
} }
#include <iostream> #include <iostream>
int main() int
main()
{ {
add_to_list(42); add_to_list(42);
std::cout<<"contains(1)="<<list_contains(1)<<", contains(42)="<<list_contains(42)<<std::endl; std::cout << "contains(1)=" << list_contains(1)
<< ", contains(42)=" << list_contains(42) << std::endl;
} }

View File

@@ -1,27 +1,29 @@
#include <mutex> #include <mutex>
class Y class Y {
{
private: private:
int some_detail; int some_detail;
mutable std::mutex m; mutable std::mutex m;
int get_detail() const
{
std::lock_guard<std::mutex> lock_a(m);
return some_detail;
}
int get_detail() const
{
std::lock_guard<std::mutex> lock_a(m);
return some_detail;
}
public: public:
Y(int sd):some_detail(sd){} Y(int sd) : some_detail(sd) {}
friend bool operator==(Y const& lhs, Y const& rhs) friend bool operator==(Y const& lhs, Y const& rhs)
{ {
if(&lhs==&rhs) if (&lhs == &rhs)
return true; return true;
int const lhs_value=lhs.get_detail(); int const lhs_value = lhs.get_detail();
int const rhs_value=rhs.get_detail(); int const rhs_value = rhs.get_detail();
return lhs_value==rhs_value; return lhs_value == rhs_value;
} }
}; };
int main() int
{} main()
{
}

View File

@@ -1,28 +1,25 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
struct some_resource struct some_resource {
{ void do_something() {}
void do_something()
{}
}; };
std::shared_ptr<some_resource> resource_ptr; std::shared_ptr<some_resource> resource_ptr;
std::mutex resource_mutex; std::mutex resource_mutex;
void foo() void
foo()
{ {
std::unique_lock<std::mutex> lk(resource_mutex); std::unique_lock<std::mutex> lk(resource_mutex);
if(!resource_ptr) if (!resource_ptr) {
{ resource_ptr.reset(new some_resource);
resource_ptr.reset(new some_resource); }
} lk.unlock();
lk.unlock(); resource_ptr->do_something();
resource_ptr->do_something();
} }
int main() int
main()
{ {
foo(); foo();
} }

View File

@@ -1,56 +1,49 @@
#include <mutex> #include <mutex>
struct connection_info struct connection_info {
{};
struct data_packet
{};
struct connection_handle
{
void send_data(data_packet const&)
{}
data_packet receive_data()
{
return data_packet();
}
}; };
struct remote_connection_manager struct data_packet {
{ };
connection_handle open(connection_info const&)
{ struct connection_handle {
return connection_handle(); void send_data(data_packet const&) {}
} data_packet receive_data() { return data_packet(); }
};
struct remote_connection_manager {
connection_handle open(connection_info const&) { return connection_handle(); }
} connection_manager; } connection_manager;
class X {
class X
{
private: private:
connection_info connection_details; connection_info connection_details;
connection_handle connection; connection_handle connection;
std::once_flag connection_init_flag; std::once_flag connection_init_flag;
void open_connection()
{
connection = connection_manager.open(connection_details);
}
void open_connection()
{
connection=connection_manager.open(connection_details);
}
public: public:
X(connection_info const& connection_details_): X(connection_info const& connection_details_)
connection_details(connection_details_) : connection_details(connection_details_)
{} {
void send_data(data_packet const& data) }
{ void send_data(data_packet const& data)
std::call_once(connection_init_flag,&X::open_connection,this); {
connection.send_data(data); std::call_once(connection_init_flag, &X::open_connection, this);
} connection.send_data(data);
data_packet receive_data() }
{ data_packet receive_data()
std::call_once(connection_init_flag,&X::open_connection,this); {
return connection.receive_data(); std::call_once(connection_init_flag, &X::open_connection, this);
} return connection.receive_data();
}
}; };
int main() int
{} main()
{
}

View File

@@ -1,30 +1,32 @@
#include <map>
#include <string>
#include <mutex>
#include <boost/thread/shared_mutex.hpp> #include <boost/thread/shared_mutex.hpp>
#include <map>
#include <mutex>
#include <string>
class dns_entry class dns_entry {
{};
class dns_cache
{
std::map<std::string,dns_entry> entries;
boost::shared_mutex entry_mutex;
public:
dns_entry find_entry(std::string const& domain)
{
boost::shared_lock<boost::shared_mutex> lk(entry_mutex);
std::map<std::string,dns_entry>::const_iterator const it=
entries.find(domain);
return (it==entries.end())?dns_entry():it->second;
}
void update_or_add_entry(std::string const& domain,
dns_entry const& dns_details)
{
std::lock_guard<boost::shared_mutex> lk(entry_mutex);
entries[domain]=dns_details;
}
}; };
int main() class dns_cache {
{} std::map<std::string, dns_entry> entries;
boost::shared_mutex entry_mutex;
public:
dns_entry find_entry(std::string const& domain)
{
boost::shared_lock<boost::shared_mutex> lk(entry_mutex);
std::map<std::string, dns_entry>::const_iterator const it =
entries.find(domain);
return (it == entries.end()) ? dns_entry() : it->second;
}
void update_or_add_entry(std::string const& domain,
dns_entry const& dns_details)
{
std::lock_guard<boost::shared_mutex> lk(entry_mutex);
entries[domain] = dns_details;
}
};
int
main()
{
}

View File

@@ -1,44 +1,46 @@
#include <mutex> #include <mutex>
class some_data class some_data {
{ int a;
int a; std::string b;
std::string b;
public: public:
void do_something() void do_something() {}
{}
}; };
class data_wrapper class data_wrapper {
{
private: private:
some_data data; some_data data;
std::mutex m; std::mutex m;
public: public:
template<typename Function> template <typename Function>
void process_data(Function func) void process_data(Function func)
{ {
std::lock_guard<std::mutex> l(m); std::lock_guard<std::mutex> l(m);
func(data); func(data);
} }
}; };
some_data* unprotected; some_data* unprotected;
void malicious_function(some_data& protected_data) void
malicious_function(some_data& protected_data)
{ {
unprotected=&protected_data; unprotected = &protected_data;
} }
data_wrapper x; data_wrapper x;
void foo() void
foo()
{ {
x.process_data(malicious_function); x.process_data(malicious_function);
unprotected->do_something(); unprotected->do_something();
} }
int main() int
main()
{ {
foo(); foo();
} }

View File

@@ -1,24 +1,29 @@
#include <deque> #include <deque>
template<typename T,typename Container=std::deque<T> > template <typename T, typename Container = std::deque<T>>
class stack class stack {
{
public: public:
explicit stack(const Container&); explicit stack(const Container&);
explicit stack(Container&& = Container()); explicit stack(Container&& = Container());
template <class Alloc> explicit stack(const Alloc&); template <class Alloc>
template <class Alloc> stack(const Container&, const Alloc&); explicit stack(const Alloc&);
template <class Alloc> stack(Container&&, const Alloc&); template <class Alloc>
template <class Alloc> stack(stack&&, const Alloc&); stack(const Container&, const Alloc&);
template <class Alloc>
stack(Container&&, const Alloc&);
template <class Alloc>
stack(stack&&, const Alloc&);
bool empty() const; bool empty() const;
size_t size() const; size_t size() const;
T& top(); T& top();
T const& top() const; T const& top() const;
void push(T const&); void push(T const&);
void push(T&&); void push(T&&);
void pop(); void pop();
void swap(stack&&); void swap(stack&&);
}; };
int main() int
{} main()
{
}

View File

@@ -1,24 +1,24 @@
#include <exception> #include <exception>
#include <memory> #include <memory>
struct empty_stack: std::exception struct empty_stack : std::exception {
{ const char* what() const throw();
const char* what() const throw();
}; };
template<typename T> template <typename T>
class threadsafe_stack class threadsafe_stack {
{
public: public:
threadsafe_stack(); threadsafe_stack();
threadsafe_stack(const threadsafe_stack&); threadsafe_stack(const threadsafe_stack&);
threadsafe_stack& operator=(const threadsafe_stack&) = delete; threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value); void push(T new_value);
std::shared_ptr<T> pop(); std::shared_ptr<T> pop();
void pop(T& value); void pop(T& value);
bool empty() const; bool empty() const;
}; };
int main() int
{} main()
{
}

View File

@@ -1,68 +1,64 @@
#include <exception> #include <exception>
#include <stack>
#include <mutex>
#include <memory> #include <memory>
#include <mutex>
#include <stack>
struct empty_stack: std::exception struct empty_stack : std::exception {
{ const char* what() const throw() { return "empty stack"; }
const char* what() const throw()
{
return "empty stack";
}
}; };
template<typename T> template <typename T>
class threadsafe_stack class threadsafe_stack {
{
private: private:
std::stack<T> data; std::stack<T> data;
mutable std::mutex m; mutable std::mutex m;
public:
threadsafe_stack(){}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
data=other.data;
}
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value) public:
{ threadsafe_stack() {}
std::lock_guard<std::mutex> lock(m); threadsafe_stack(const threadsafe_stack& other)
data.push(new_value); {
} std::lock_guard<std::mutex> lock(other.m);
std::shared_ptr<T> pop() data = other.data;
{ }
std::lock_guard<std::mutex> lock(m); threadsafe_stack& operator=(const threadsafe_stack&) = delete;
if(data.empty()) throw empty_stack();
std::shared_ptr<T> const res(std::make_shared<T>(data.top())); void push(T new_value)
data.pop(); {
return res; std::lock_guard<std::mutex> lock(m);
} data.push(new_value);
void pop(T& value) }
{ std::shared_ptr<T> pop()
std::lock_guard<std::mutex> lock(m); {
if(data.empty()) throw empty_stack(); std::lock_guard<std::mutex> lock(m);
value=data.top(); if (data.empty())
data.pop(); throw empty_stack();
} std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
bool empty() const data.pop();
{ return res;
std::lock_guard<std::mutex> lock(m); }
return data.empty(); void pop(T& value)
} {
std::lock_guard<std::mutex> lock(m);
if (data.empty())
throw empty_stack();
value = data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
}; };
int main() int
main()
{ {
threadsafe_stack<int> si; threadsafe_stack<int> si;
si.push(5); si.push(5);
si.pop(); si.pop();
if(!si.empty()) if (!si.empty()) {
{ int x;
int x; si.pop(x);
si.pop(x); }
}
} }

View File

@@ -1,29 +1,33 @@
#include <mutex> #include <mutex>
class some_big_object class some_big_object {
{};
void swap(some_big_object& lhs,some_big_object& rhs)
{}
class X
{
private:
some_big_object some_detail;
mutable std::mutex m;
public:
X(some_big_object const& sd):some_detail(sd){}
friend void swap(X& lhs, X& rhs)
{
if(&lhs==&rhs)
return;
std::lock(lhs.m,rhs.m);
std::lock_guard<std::mutex> lock_a(lhs.m,std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m,std::adopt_lock);
swap(lhs.some_detail,rhs.some_detail);
}
}; };
int main() void
{} swap(some_big_object& lhs, some_big_object& rhs)
{
}
class X {
private:
some_big_object some_detail;
mutable std::mutex m;
public:
X(some_big_object const& sd) : some_detail(sd) {}
friend void swap(X& lhs, X& rhs)
{
if (&lhs == &rhs)
return;
std::lock(lhs.m, rhs.m);
std::lock_guard<std::mutex> lock_a(lhs.m, std::adopt_lock);
std::lock_guard<std::mutex> lock_b(rhs.m, std::adopt_lock);
swap(lhs.some_detail, rhs.some_detail);
}
};
int
main()
{
}

View File

@@ -1,64 +1,68 @@
#include <mutex> #include <mutex>
class hierarchical_mutex class hierarchical_mutex {
{
public: public:
explicit hierarchical_mutex(unsigned level) explicit hierarchical_mutex(unsigned level) {}
{}
void lock()
{}
void unlock()
{}
};
void lock() {}
void unlock() {}
};
hierarchical_mutex high_level_mutex(10000); hierarchical_mutex high_level_mutex(10000);
hierarchical_mutex low_level_mutex(5000); hierarchical_mutex low_level_mutex(5000);
int do_low_level_stuff() int
do_low_level_stuff()
{ {
return 42; return 42;
} }
int
int low_level_func() low_level_func()
{ {
std::lock_guard<hierarchical_mutex> lk(low_level_mutex); std::lock_guard<hierarchical_mutex> lk(low_level_mutex);
return do_low_level_stuff(); return do_low_level_stuff();
} }
void high_level_stuff(int some_param) void
{} high_level_stuff(int some_param)
void high_level_func()
{ {
std::lock_guard<hierarchical_mutex> lk(high_level_mutex);
high_level_stuff(low_level_func());
} }
void thread_a() void
high_level_func()
{ {
high_level_func(); std::lock_guard<hierarchical_mutex> lk(high_level_mutex);
high_level_stuff(low_level_func());
}
void
thread_a()
{
high_level_func();
} }
hierarchical_mutex other_mutex(100); hierarchical_mutex other_mutex(100);
void do_other_stuff() void
{} do_other_stuff()
void other_stuff()
{ {
high_level_func();
do_other_stuff();
} }
void thread_b() void
other_stuff()
{ {
std::lock_guard<hierarchical_mutex> lk(other_mutex); high_level_func();
other_stuff(); do_other_stuff();
} }
int main() void
{} thread_b()
{
std::lock_guard<hierarchical_mutex> lk(other_mutex);
other_stuff();
}
int
main()
{
}

View File

@@ -1,56 +1,55 @@
#include <mutex> #include <mutex>
#include <stdexcept> #include <stdexcept>
class hierarchical_mutex class hierarchical_mutex {
{ std::mutex internal_mutex;
std::mutex internal_mutex; unsigned long const hierarchy_value;
unsigned long const hierarchy_value; unsigned long previous_hierarchy_value;
unsigned long previous_hierarchy_value; static thread_local unsigned long this_thread_hierarchy_value;
static thread_local unsigned long this_thread_hierarchy_value;
void check_for_hierarchy_violation() void check_for_hierarchy_violation()
{ {
if(this_thread_hierarchy_value <= hierarchy_value) if (this_thread_hierarchy_value <= hierarchy_value) {
{ throw std::logic_error("mutex hierarchy violated");
throw std::logic_error("mutex hierarchy violated");
}
}
void update_hierarchy_value()
{
previous_hierarchy_value=this_thread_hierarchy_value;
this_thread_hierarchy_value=hierarchy_value;
} }
}
void update_hierarchy_value()
{
previous_hierarchy_value = this_thread_hierarchy_value;
this_thread_hierarchy_value = hierarchy_value;
}
public: public:
explicit hierarchical_mutex(unsigned long value): explicit hierarchical_mutex(unsigned long value)
hierarchy_value(value), : hierarchy_value(value), previous_hierarchy_value(0)
previous_hierarchy_value(0) {
{} }
void lock() void lock()
{ {
check_for_hierarchy_violation(); check_for_hierarchy_violation();
internal_mutex.lock(); internal_mutex.lock();
update_hierarchy_value(); update_hierarchy_value();
} }
void unlock() void unlock()
{ {
this_thread_hierarchy_value=previous_hierarchy_value; this_thread_hierarchy_value = previous_hierarchy_value;
internal_mutex.unlock(); internal_mutex.unlock();
} }
bool try_lock() bool try_lock()
{ {
check_for_hierarchy_violation(); check_for_hierarchy_violation();
if(!internal_mutex.try_lock()) if (!internal_mutex.try_lock())
return false; return false;
update_hierarchy_value(); update_hierarchy_value();
return true; return true;
} }
}; };
thread_local unsigned long thread_local unsigned long hierarchical_mutex::this_thread_hierarchy_value(
hierarchical_mutex::this_thread_hierarchy_value(ULONG_MAX); ULONG_MAX);
int main() int
main()
{ {
hierarchical_mutex m1(42); hierarchical_mutex m1(42);
hierarchical_mutex m2(2000); hierarchical_mutex m2(2000);
} }

View File

@@ -1,29 +1,33 @@
#include <mutex> #include <mutex>
class some_big_object class some_big_object {
{};
void swap(some_big_object& lhs,some_big_object& rhs)
{}
class X
{
private:
some_big_object some_detail;
mutable std::mutex m;
public:
X(some_big_object const& sd):some_detail(sd){}
friend void swap(X& lhs, X& rhs)
{
if(&lhs==&rhs)
return;
std::unique_lock<std::mutex> lock_a(lhs.m,std::defer_lock);
std::unique_lock<std::mutex> lock_b(rhs.m,std::defer_lock);
std::lock(lock_a,lock_b);
swap(lhs.some_detail,rhs.some_detail);
}
}; };
int main() void
{} swap(some_big_object& lhs, some_big_object& rhs)
{
}
class X {
private:
some_big_object some_detail;
mutable std::mutex m;
public:
X(some_big_object const& sd) : some_detail(sd) {}
friend void swap(X& lhs, X& rhs)
{
if (&lhs == &rhs)
return;
std::unique_lock<std::mutex> lock_a(lhs.m, std::defer_lock);
std::unique_lock<std::mutex> lock_b(rhs.m, std::defer_lock);
std::lock(lock_a, lock_b);
swap(lhs.some_detail, rhs.some_detail);
}
};
int
main()
{
}

View File

@@ -1,64 +1,70 @@
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <thread> #include <mutex>
#include <queue> #include <queue>
#include <thread>
bool more_data_to_prepare() bool
more_data_to_prepare()
{ {
return false; return false;
} }
struct data_chunk struct data_chunk {
{}; };
data_chunk prepare_data() data_chunk
prepare_data()
{ {
return data_chunk(); return data_chunk();
} }
void process(data_chunk&) void
{} process(data_chunk&)
bool is_last_chunk(data_chunk&)
{ {
return true; }
bool
is_last_chunk(data_chunk&)
{
return true;
} }
std::mutex mut; std::mutex mut;
std::queue<data_chunk> data_queue; std::queue<data_chunk> data_queue;
std::condition_variable data_cond; std::condition_variable data_cond;
void data_preparation_thread() void
data_preparation_thread()
{ {
while(more_data_to_prepare()) while (more_data_to_prepare()) {
{ data_chunk const data = prepare_data();
data_chunk const data=prepare_data(); std::lock_guard<std::mutex> lk(mut);
std::lock_guard<std::mutex> lk(mut); data_queue.push(data);
data_queue.push(data); data_cond.notify_one();
data_cond.notify_one(); }
}
} }
void data_processing_thread() void
data_processing_thread()
{ {
while(true) while (true) {
{ std::unique_lock<std::mutex> lk(mut);
std::unique_lock<std::mutex> lk(mut); data_cond.wait(lk, [] { return !data_queue.empty(); });
data_cond.wait(lk,[]{return !data_queue.empty();}); data_chunk data = data_queue.front();
data_chunk data=data_queue.front(); data_queue.pop();
data_queue.pop(); lk.unlock();
lk.unlock(); process(data);
process(data); if (is_last_chunk(data))
if(is_last_chunk(data)) break;
break; }
}
} }
int main() int
main()
{ {
std::thread t1(data_preparation_thread); std::thread t1(data_preparation_thread);
std::thread t2(data_processing_thread); std::thread t2(data_processing_thread);
t1.join(); t1.join();
t2.join(); t2.join();
} }

View File

@@ -1,27 +1,22 @@
#include <future> #include <future>
void process_connections(connection_set& connections) void
process_connections(connection_set& connections)
{ {
while(!done(connections)) while (!done(connections)) {
{ for (connection_iterator connection = connections.begin(),
for(connection_iterator end = connections.end();
connection=connections.begin(),end=connections.end(); connection != end;
connection!=end; ++connection) {
++connection) if (connection->has_incoming_data()) {
{ data_packet data = connection->incoming();
if(connection->has_incoming_data()) std::promise<payload_type>& p = connection->get_promise(data.id);
{ p.set_value(data.payload);
data_packet data=connection->incoming(); }
std::promise<payload_type>& p= if (connection->has_outgoing_data()) {
connection->get_promise(data.id); outgoing_packet data = connection->top_of_outgoing_queue();
p.set_value(data.payload); connection->send(data.payload);
} data.promise.set_value(true);
if(connection->has_outgoing_data()) }
{
outgoing_packet data=
connection->top_of_outgoing_queue();
connection->send(data.payload);
data.promise.set_value(true);
}
}
} }
}
} }

View File

@@ -1,18 +1,18 @@
#include <chrono>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <chrono>
std::condition_variable cv; std::condition_variable cv;
bool done; bool done;
std::mutex m; std::mutex m;
bool wait_loop() bool
wait_loop()
{ {
auto const timeout= std::chrono::steady_clock::now()+ auto const timeout =
std::chrono::milliseconds(500); std::chrono::steady_clock::now() + std::chrono::milliseconds(500);
std::unique_lock<std::mutex> lk(m); std::unique_lock<std::mutex> lk(m);
while(!done) while (!done) {
{ if (cv.wait_until(lk, timeout) == std::cv_status::timeout)
if(cv.wait_until(lk,timeout)==std::cv_status::timeout) break;
break; }
} return done;
return done;
} }

View File

@@ -1,24 +1,21 @@
template<typename T> template <typename T>
std::list<T> sequential_quick_sort(std::list<T> input) std::list<T>
sequential_quick_sort(std::list<T> input)
{ {
if(input.empty()) if (input.empty()) {
{ return input;
return input; }
} std::list<T> result;
std::list<T> result; result.splice(result.begin(), input, input.begin());
result.splice(result.begin(),input,input.begin()); T const& pivot = *result.begin();
T const& pivot=*result.begin(); auto divide_point = std::partition(
auto divide_point=std::partition(input.begin(),input.end(), input.begin(), input.end(), [&](T const& t) { return t < pivot; });
[&](T const& t){return t<pivot;}); std::list<T> lower_part;
std::list<T> lower_part; lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
lower_part.splice(lower_part.end(),input,input.begin(), auto new_lower(sequential_quick_sort(std::move(lower_part)));
divide_point); auto new_higher(sequential_quick_sort(std::move(input)));
auto new_lower( result.splice(result.end(), new_higher);
sequential_quick_sort(std::move(lower_part))); Using synchronization of operations to simplify code result.splice(
auto new_higher( result.begin(), new_lower);
sequential_quick_sort(std::move(input))); return result;
result.splice(result.end(),new_higher);
Using synchronization of operations to simplify code
result.splice(result.begin(),new_lower);
return result;
} }

View File

@@ -1,23 +1,21 @@
template<typename T> template <typename T>
std::list<T> parallel_quick_sort(std::list<T> input) std::list<T>
parallel_quick_sort(std::list<T> input)
{ {
if(input.empty()) if (input.empty()) {
{ return input;
return input; }
} std::list<T> result;
std::list<T> result; result.splice(result.begin(), input, input.begin());
result.splice(result.begin(),input,input.begin()); T const& pivot = *result.begin();
T const& pivot=*result.begin(); auto divide_point = std::partition(
auto divide_point=std::partition(input.begin(),input.end(), input.begin(), input.end(), [&](T const& t) { return t < pivot; });
[&](T const& t){return t<pivot;}); std::list<T> lower_part;
std::list<T> lower_part; lower_part.splice(lower_part.end(), input, input.begin(), divide_point);
lower_part.splice(lower_part.end(),input,input.begin(), std::future<std::list<T>> new_lower(
divide_point); std::async(&parallel_quick_sort<T>, std::move(lower_part)));
std::future<std::list<T> > new_lower( auto new_higher(parallel_quick_sort(std::move(input)));
std::async(&parallel_quick_sort<T>,std::move(lower_part))); result.splice(result.end(), new_higher);
auto new_higher( result.splice(result.begin(), new_lower.get());
parallel_quick_sort(std::move(input))); return result;
result.splice(result.end(),new_higher);
result.splice(result.begin(),new_lower.get());
return result;
} }

View File

@@ -1,12 +1,11 @@
template<typename F,typename A> template <typename F, typename A>
std::future<std::result_of<F(A&&)>::type> std::future<std::result_of<F(A&&)>::type>
spawn_task(F&& f,A&& a) spawn_task(F&& f, A&& a)
{ {
typedef std::result_of<F(A&&)>::type result_type; typedef std::result_of<F(A &&)>::type result_type;
std::packaged_task<result_type(A&&)> std::packaged_task<result_type(A &&)> task(std::move(f));
task(std::move(f)); std::future<result_type> res(task.get_future());
std::future<result_type> res(task.get_future()); std::thread t(std::move(task), std::move(a));
std::thread t(std::move(task),std::move(a)); t.detach();
t.detach(); return res;
return res;
} }

View File

@@ -1,43 +1,35 @@
struct card_inserted struct card_inserted {
{ std::string account;
std::string account;
}; };
class atm class atm {
{ messaging::receiver incoming;
messaging::receiver incoming; messaging::sender bank;
messaging::sender bank; messaging::sender interface_hardware;
messaging::sender interface_hardware; void (atm::*state)();
void (atm::*state)(); std::string account;
std::string account; std::string pin;
std::string pin; void waiting_for_card()
void waiting_for_card() {
{ interface_hardware.send(display_enter_card());
interface_hardware.send(display_enter_card()); incoming.wait().handle<card_inserted>([&](card_inserted const& msg) {
incoming.wait() account = msg.account;
.handle<card_inserted>( pin = "";
[&](card_inserted const& msg) interface_hardware.send(display_enter_pin());
{ state = &atm::getting_pin;
account=msg.account; });
pin=""; }
interface_hardware.send(display_enter_pin()); void getting_pin();
state=&atm::getting_pin;
}
);
}
void getting_pin();
public: public:
void run() void run()
{ {
state=&atm::waiting_for_card; state = &atm::waiting_for_card;
try try {
{ for (;;) {
for(;;) (this->*state)();
{ }
(this->*state)();
}
}
catch(messaging::close_queue const&)
{
}
} }
catch (messaging::close_queue const&) {
}
}
}; };

View File

@@ -1,31 +1,20 @@
void atm::getting_pin() void
atm::getting_pin()
{ {
incoming.wait() incoming.wait()
.handle<digit_pressed>( .handle<digit_pressed>([&](digit_pressed const& msg) {
[&](digit_pressed const& msg) unsigned const pin_length = 4;
{ pin += msg.digit;
unsigned const pin_length=4; if (pin.length() == pin_length) {
pin+=msg.digit; bank.send(verify_pin(account, pin, incoming));
if(pin.length()==pin_length) state = &atm::verifying_pin;
{ }
bank.send(verify_pin(account,pin,incoming)); })
state=&atm::verifying_pin; .handle<clear_last_pressed>([&](clear_last_pressed const& msg) {
} if (!pin.empty()) {
} pin.resize(pin.length() - 1);
) }
.handle<clear_last_pressed>( })
[&](clear_last_pressed const& msg) .handle<cancel_pressed>(
{ [&](cancel_pressed const& msg) { state = &atm::done_processing; });
if(!pin.empty())
{
pin.resize(pin.length()-1);
}
}
)
.handle<cancel_pressed>(
[&](cancel_pressed const& msg)
{
state=&atm::done_processing;
}
);
} }

View File

@@ -1,30 +1,36 @@
template <class T, class Container = std::deque<T> > template <class T, class Container = std::deque<T>>
class queue { class queue {
public: public:
explicit queue(const Container&); explicit queue(const Container&);
explicit queue(Container&& = Container()); explicit queue(Container&& = Container());
queue(queue&& q); queue(queue&& q);
template <class Alloc> explicit queue(const Alloc&); template <class Alloc>
template <class Alloc> queue(const Container&, const Alloc&); explicit queue(const Alloc&);
template <class Alloc> queue(Container&&, const Alloc&); template <class Alloc>
template <class Alloc> queue(queue&&, const Alloc&); queue(const Container&, const Alloc&);
template <class Alloc>
queue(Container&&, const Alloc&);
template <class Alloc>
queue(queue&&, const Alloc&);
queue& operator=(queue&& q); queue& operator=(queue&& q);
void swap(queue&& q); void swap(queue&& q);
bool empty() const; bool empty() const;
size_type size() const; size_type size() const;
T& front(); T& front();
const T& front() const; const T& front() const;
T& back(); T& back();
const T& back() const; const T& back() const;
void push(const T& x); void push(const T& x);
void push(T&& x); void push(T&& x);
void pop(); void pop();
}; };
int main() int
{} main()
{
}

View File

@@ -1,22 +1,23 @@
#include <memory> #include <memory>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
public: public:
threadsafe_queue(); threadsafe_queue();
threadsafe_queue(const threadsafe_queue&); threadsafe_queue(const threadsafe_queue&);
threadsafe_queue& operator=(const threadsafe_queue&) = delete; threadsafe_queue& operator=(const threadsafe_queue&) = delete;
void push(T new_value); void push(T new_value);
bool try_pop(T& value);
std::shared_ptr<T> try_pop();
void wait_and_pop(T& value); bool try_pop(T& value);
std::shared_ptr<T> wait_and_pop(); std::shared_ptr<T> try_pop();
bool empty() const; void wait_and_pop(T& value);
std::shared_ptr<T> wait_and_pop();
bool empty() const;
}; };
int main() int
{} main()
{
}

View File

@@ -1,33 +1,32 @@
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <mutex>
#include <queue> #include <queue>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
std::mutex mut; std::mutex mut;
std::queue<T> data_queue; std::queue<T> data_queue;
std::condition_variable data_cond; std::condition_variable data_cond;
public:
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value);
data_cond.notify_one();
}
void wait_and_pop(T& value) public:
{ void push(T new_value)
std::unique_lock<std::mutex> lk(mut); {
data_cond.wait(lk,[this]{return !data_queue.empty();}); std::lock_guard<std::mutex> lk(mut);
value=data_queue.front(); data_queue.push(new_value);
data_queue.pop(); data_cond.notify_one();
} }
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this] { return !data_queue.empty(); });
value = data_queue.front();
data_queue.pop();
}
}; };
struct data_chunk {
struct data_chunk };
{};
data_chunk prepare_data(); data_chunk prepare_data();
bool more_data_to_prepare(); bool more_data_to_prepare();
@@ -36,23 +35,23 @@ bool is_last_chunk(data_chunk);
threadsafe_queue<data_chunk> data_queue; threadsafe_queue<data_chunk> data_queue;
void data_preparation_thread() void
data_preparation_thread()
{ {
while(more_data_to_prepare()) while (more_data_to_prepare()) {
{ data_chunk const data = prepare_data();
data_chunk const data=prepare_data(); data_queue.push(data);
data_queue.push(data); }
}
} }
void data_processing_thread() void
data_processing_thread()
{ {
while(true) while (true) {
{ data_chunk data;
data_chunk data; data_queue.wait_and_pop(data);
data_queue.wait_and_pop(data); process(data);
process(data); if (is_last_chunk(data))
if(is_last_chunk(data)) break;
break; }
}
} }

View File

@@ -1,73 +1,74 @@
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <queue>
#include <memory> #include <memory>
#include <mutex>
#include <queue>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
mutable std::mutex mut; mutable std::mutex mut;
std::queue<T> data_queue; std::queue<T> data_queue;
std::condition_variable data_cond; std::condition_variable data_cond;
public: public:
threadsafe_queue() threadsafe_queue() {}
{} threadsafe_queue(threadsafe_queue const& other)
threadsafe_queue(threadsafe_queue const& other) {
{ std::lock_guard<std::mutex> lk(other.mut);
std::lock_guard<std::mutex> lk(other.mut); data_queue = other.data_queue;
data_queue=other.data_queue; }
}
void push(T new_value) void push(T new_value)
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_queue.push(new_value); data_queue.push(new_value);
data_cond.notify_one(); data_cond.notify_one();
} }
void wait_and_pop(T& value) void wait_and_pop(T& value)
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
value=data_queue.front(); value = data_queue.front();
data_queue.pop(); data_queue.pop();
} }
std::shared_ptr<T> wait_and_pop() std::shared_ptr<T> wait_and_pop()
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop(); data_queue.pop();
return res; return res;
} }
bool try_pop(T& value) bool try_pop(T& value)
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty) if (data_queue.empty)
return false; return false;
value=data_queue.front(); value = data_queue.front();
data_queue.pop(); data_queue.pop();
} }
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty()) if (data_queue.empty())
return std::shared_ptr<T>(); return std::shared_ptr<T>();
std::shared_ptr<T> res(std::make_shared<T>(data_queue.front())); std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
data_queue.pop(); data_queue.pop();
return res; return res;
} }
bool empty() const bool empty() const
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
return data_queue.empty(); return data_queue.empty();
} }
}; };
int main() int
{} main()
{
}

View File

@@ -1,16 +1,20 @@
#include <future> #include <future>
#include <iostream> #include <iostream>
int find_the_answer_to_ltuae() int
find_the_answer_to_ltuae()
{ {
return 42; return 42;
} }
void do_other_stuff() void
{} do_other_stuff()
int main()
{ {
std::future<int> the_answer=std::async(find_the_answer_to_ltuae); }
do_other_stuff();
std::cout<<"The answer is "<<the_answer.get()<<std::endl; int
main()
{
std::future<int> the_answer = std::async(find_the_answer_to_ltuae);
do_other_stuff();
std::cout << "The answer is " << the_answer.get() << std::endl;
} }

View File

@@ -1,34 +1,30 @@
#include <string>
#include <future> #include <future>
#include <string>
struct X struct X {
{ void foo(int, std::string const&);
void foo(int,std::string const&); std::string bar(std::string const&);
std::string bar(std::string const&);
}; };
X x; X x;
auto f1=std::async(&X::foo,&x,42,"hello"); auto f1 = std::async(&X::foo, &x, 42, "hello");
auto f2=std::async(&X::bar,x,"goodbye"); auto f2 = std::async(&X::bar, x, "goodbye");
struct Y struct Y {
{ double operator()(double);
double operator()(double);
}; };
Y y; Y y;
auto f3=std::async(Y(),3.141); auto f3 = std::async(Y(), 3.141);
auto f4=std::async(std::ref(y),2.718); auto f4 = std::async(std::ref(y), 2.718);
X baz(X&); X baz(X&);
auto f6=std::async(baz,std::ref(x)); auto f6 = std::async(baz, std::ref(x));
class move_only class move_only {
{
public: public:
move_only(); move_only();
move_only(move_only&&); move_only(move_only&&);
move_only(move_only const&) = delete; move_only(move_only const&) = delete;
move_only& operator=(move_only&&); move_only& operator =(move_only&&);
move_only& operator=(move_only const&) = delete; move_only& operator=(move_only const&) = delete;
void operator()(); void operator()();
}; };
auto f5=std::async(move_only()); auto f5 = std::async(move_only());

View File

@@ -1,9 +1,8 @@
template<> template <>
class packaged_task<std::string(std::vector<char>*,int)> class packaged_task<std::string(std::vector<char>*, int)> {
{
public: public:
template<typename Callable> template <typename Callable>
explicit packaged_task(Callable&& f); explicit packaged_task(Callable&& f);
std::future<std::string> get_future(); std::future<std::string> get_future();
void operator()(std::vector<char>*,int); void operator()(std::vector<char>*, int);
}; };

View File

@@ -1,40 +1,41 @@
#include <deque> #include <deque>
#include <mutex>
#include <future> #include <future>
#include <mutex>
#include <thread> #include <thread>
#include <utility> #include <utility>
std::mutex m; std::mutex m;
std::deque<std::packaged_task<void()> > tasks; std::deque<std::packaged_task<void()>> tasks;
bool gui_shutdown_message_received(); bool gui_shutdown_message_received();
void get_and_process_gui_message(); void get_and_process_gui_message();
void gui_thread() void
gui_thread()
{ {
while(!gui_shutdown_message_received()) while (!gui_shutdown_message_received()) {
get_and_process_gui_message();
std::packaged_task<void()> task;
{ {
get_and_process_gui_message(); std::lock_guard<std::mutex> lk(m);
std::packaged_task<void()> task; if (tasks.empty())
{ continue;
std::lock_guard<std::mutex> lk(m); task = std::move(tasks.front());
if(tasks.empty()) tasks.pop_front();
continue;
task=std::move(tasks.front());
tasks.pop_front();
}
task();
} }
task();
}
} }
std::thread gui_bg_thread(gui_thread); std::thread gui_bg_thread(gui_thread);
template<typename Func> template <typename Func>
std::future<void> post_task_for_gui_thread(Func f) std::future<void>
post_task_for_gui_thread(Func f)
{ {
std::packaged_task<void()> task(f); std::packaged_task<void()> task(f);
std::future<void> res=task.get_future(); std::future<void> res = task.get_future();
std::lock_guard<std::mutex> lk(m); std::lock_guard<std::mutex> lk(m);
tasks.push_back(std::move(task)); tasks.push_back(std::move(task));
return res; return res;
} }

View File

@@ -1,16 +1,12 @@
class spinlock_mutex class spinlock_mutex {
{ std::atomic_flag flag;
std::atomic_flag flag;
public: public:
spinlock_mutex(): spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {}
flag(ATOMIC_FLAG_INIT) void lock()
{} {
void lock() while (flag.test_and_set(std::memory_order_acquire))
{ ;
while(flag.test_and_set(std::memory_order_acquire)); }
} void unlock() { flag.clear(std::memory_order_release); }
void unlock()
{
flag.clear(std::memory_order_release);
}
}; };

View File

@@ -1,39 +1,40 @@
#include <assert.h>
#include <atomic>
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic> struct X {
#include <assert.h> int i;
struct X std::string s;
{
int i;
std::string s;
}; };
std::atomic<X*> p; std::atomic<X*> p;
std::atomic<int> a; std::atomic<int> a;
void create_x() void
create_x()
{ {
X* x=new X; X* x = new X;
x->i=42; x->i = 42;
x->s="hello"; x->s = "hello";
a.store(99,std::memory_order_relaxed); a.store(99, std::memory_order_relaxed);
p.store(x,std::memory_order_release); p.store(x, std::memory_order_release);
} }
void use_x() void
use_x()
{ {
X* x; X* x;
while(!(x=p.load(std::memory_order_consume))) while (!(x = p.load(std::memory_order_consume)))
std::this_thread::sleep_for(std::chrono::microseconds(1)); std::this_thread::sleep_for(std::chrono::microseconds(1));
assert(x->i==42); assert(x->i == 42);
assert(x->s=="hello"); assert(x->s == "hello");
assert(a.load(std::memory_order_relaxed)==99); assert(a.load(std::memory_order_relaxed) == 99);
} }
int main() int
main()
{ {
std::thread t1(create_x); std::thread t1(create_x);
std::thread t2(use_x); std::thread t2(use_x);
t1.join(); t1.join();
t2.join(); t2.join();
} }

View File

@@ -4,38 +4,38 @@
std::vector<int> queue_data; std::vector<int> queue_data;
std::atomic<int> count; std::atomic<int> count;
void populate_queue() void
populate_queue()
{ {
unsigned const number_of_items=20; unsigned const number_of_items = 20;
queue_data.clear(); queue_data.clear();
for(unsigned i=0;i<number_of_items;++i) for (unsigned i = 0; i < number_of_items; ++i) {
{ queue_data.push_back(i);
queue_data.push_back(i); }
}
count.store(number_of_items, std::memory_order_release);
count.store(number_of_items,std::memory_order_release);
} }
void consume_queue_items() void
consume_queue_items()
{ {
while(true) while (true) {
{ int item_index;
int item_index; if ((item_index = count.fetch_sub(1, std::memory_order_acquire)) <= 0) {
if((item_index=count.fetch_sub(1,std::memory_order_acquire))<=0) wait_for_more_items();
{ continue;
wait_for_more_items();
continue;
}
process(queue_data[item_index-1]);
} }
process(queue_data[item_index - 1]);
}
} }
int main() int
main()
{ {
std::thread a(populate_queue); std::thread a(populate_queue);
std::thread b(consume_queue_items); std::thread b(consume_queue_items);
std::thread c(consume_queue_items); std::thread c(consume_queue_items);
a.join(); a.join();
b.join(); b.join();
c.join(); c.join();
} }

View File

@@ -1,33 +1,37 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<bool> x,y; std::atomic<bool> x, y;
std::atomic<int> z; std::atomic<int> z;
void write_x_then_y() void
write_x_then_y()
{ {
x.store(true,std::memory_order_relaxed); x.store(true, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
y.store(true,std::memory_order_relaxed); y.store(true, std::memory_order_relaxed);
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_relaxed)); while (!y.load(std::memory_order_relaxed))
std::atomic_thread_fence(std::memory_order_acquire); ;
if(x.load(std::memory_order_relaxed)) std::atomic_thread_fence(std::memory_order_acquire);
++z; if (x.load(std::memory_order_relaxed))
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x_then_y); std::thread a(write_x_then_y);
std::thread b(read_y_then_x); std::thread b(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,34 +1,38 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
bool x=false; bool x = false;
std::atomic<bool> y; std::atomic<bool> y;
std::atomic<int> z; std::atomic<int> z;
void write_x_then_y() void
write_x_then_y()
{ {
x=true; x = true;
std::atomic_thread_fence(std::memory_order_release); std::atomic_thread_fence(std::memory_order_release);
y.store(true,std::memory_order_relaxed); y.store(true, std::memory_order_relaxed);
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_relaxed)); while (!y.load(std::memory_order_relaxed))
std::atomic_thread_fence(std::memory_order_acquire); ;
if(x) std::atomic_thread_fence(std::memory_order_acquire);
++z; if (x)
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x_then_y); std::thread a(write_x_then_y);
std::thread b(read_y_then_x); std::thread b(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,22 +1,23 @@
#include <vector>
#include <atomic> #include <atomic>
#include <iostream>
#include <chrono> #include <chrono>
#include <iostream>
#include <thread> #include <thread>
#include <vector>
std::vector<int> data; std::vector<int> data;
std::atomic_bool data_ready(false); std::atomic_bool data_ready(false);
void reader_thread() void
reader_thread()
{ {
while(!data_ready.load()) while (!data_ready.load()) {
{ std::this_thread::sleep_for(std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1)); }
} std::cout << "The answer=" << data[0] << "\n";
std::cout<<"The answer="<<data[0]<<"\n";
} }
void writer_thread() void
writer_thread()
{ {
data.push_back(42); data.push_back(42);
data_ready=true; data_ready = true;
} }

View File

@@ -1,17 +1,20 @@
#include <iostream> #include <iostream>
void foo(int a,int b) void
foo(int a, int b)
{ {
std::cout<<a<<,<<b<<std::endl; std::cout << a <<,<< b << std::endl;
} }
int get_num() int
get_num()
{ {
static int i=0; static int i = 0;
return ++i; return ++i;
} }
int main() int
main()
{ {
foo(get_num(),get_num()); foo(get_num(), get_num());
} }

View File

@@ -1,46 +1,53 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<bool> x,y; std::atomic<bool> x, y;
std::atomic<int> z; std::atomic<int> z;
void write_x() void
write_x()
{ {
x.store(true,std::memory_order_seq_cst); x.store(true, std::memory_order_seq_cst);
} }
void write_y() void
write_y()
{ {
y.store(true,std::memory_order_seq_cst); y.store(true, std::memory_order_seq_cst);
} }
void read_x_then_y() void
read_x_then_y()
{ {
while(!x.load(std::memory_order_seq_cst)); while (!x.load(std::memory_order_seq_cst))
if(y.load(std::memory_order_seq_cst)) ;
++z; if (y.load(std::memory_order_seq_cst))
++z;
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_seq_cst)); while (!y.load(std::memory_order_seq_cst))
if(x.load(std::memory_order_seq_cst)) ;
++z; if (x.load(std::memory_order_seq_cst))
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x); std::thread a(write_x);
std::thread b(write_y); std::thread b(write_y);
std::thread c(read_x_then_y); std::thread c(read_x_then_y);
std::thread d(read_y_then_x); std::thread d(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
c.join(); c.join();
d.join(); d.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,31 +1,35 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<bool> x,y; std::atomic<bool> x, y;
std::atomic<int> z; std::atomic<int> z;
void write_x_then_y() void
write_x_then_y()
{ {
x.store(true,std::memory_order_relaxed); x.store(true, std::memory_order_relaxed);
y.store(true,std::memory_order_relaxed); y.store(true, std::memory_order_relaxed);
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_relaxed)); while (!y.load(std::memory_order_relaxed))
if(x.load(std::memory_order_relaxed)) ;
++z; if (x.load(std::memory_order_relaxed))
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x_then_y); std::thread a(write_x_then_y);
std::thread b(read_y_then_x); std::thread b(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,74 +1,72 @@
#include <thread>
#include <atomic> #include <atomic>
#include <iostream> #include <iostream>
#include <thread>
std::atomic<int> x(0),y(0),z(0); std::atomic<int> x(0), y(0), z(0);
std::atomic<bool> go(false); std::atomic<bool> go(false);
unsigned const loop_count=10; unsigned const loop_count = 10;
struct read_values struct read_values {
{ int x, y, z;
int x,y,z;
}; };
read_values values1[loop_count]; read_values values1[loop_count];
read_values values2[loop_count]; read_values values2[loop_count];
read_values values3[loop_count]; read_values values3[loop_count];
read_values values4[loop_count]; read_values values4[loop_count];
read_values values5[loop_count]; read_values values5[loop_count];
void increment(std::atomic<int>* var_to_inc,read_values* values) void
increment(std::atomic<int>* var_to_inc, read_values* values)
{ {
while(!go) while (!go) std::this_thread::yield();
std::this_thread::yield(); for (unsigned i = 0; i < loop_count; ++i) {
for(unsigned i=0;i<loop_count;++i) values[i].x = x.load(std::memory_order_relaxed);
{ values[i].y = y.load(std::memory_order_relaxed);
values[i].x=x.load(std::memory_order_relaxed); values[i].z = z.load(std::memory_order_relaxed);
values[i].y=y.load(std::memory_order_relaxed); var_to_inc->store(i + 1, std::memory_order_relaxed);
values[i].z=z.load(std::memory_order_relaxed); std::this_thread::yield();
var_to_inc->store(i+1,std::memory_order_relaxed); }
std::this_thread::yield();
}
} }
void read_vals(read_values* values) void
read_vals(read_values* values)
{ {
while(!go) while (!go) std::this_thread::yield();
std::this_thread::yield(); for (unsigned i = 0; i < loop_count; ++i) {
for(unsigned i=0;i<loop_count;++i) values[i].x = x.load(std::memory_order_relaxed);
{ values[i].y = y.load(std::memory_order_relaxed);
values[i].x=x.load(std::memory_order_relaxed); values[i].z = z.load(std::memory_order_relaxed);
values[i].y=y.load(std::memory_order_relaxed); std::this_thread::yield();
values[i].z=z.load(std::memory_order_relaxed); }
std::this_thread::yield();
}
} }
void print(read_values* v) void
print(read_values* v)
{ {
for(unsigned i=0;i<loop_count;++i) for (unsigned i = 0; i < loop_count; ++i) {
{ if (i)
if(i) std::cout << ",";
std::cout<<","; std::cout << "(" << v[i].x << "," << v[i].y << "," << v[i].z << ")";
std::cout<<"("<<v[i].x<<","<<v[i].y<<","<<v[i].z<<")"; }
} std::cout << std::endl;
std::cout<<std::endl;
} }
int main() int
main()
{ {
std::thread t1(increment,&x,values1); std::thread t1(increment, &x, values1);
std::thread t2(increment,&y,values2); std::thread t2(increment, &y, values2);
std::thread t3(increment,&z,values3); std::thread t3(increment, &z, values3);
std::thread t4(read_vals,values4); std::thread t4(read_vals, values4);
std::thread t5(read_vals,values5); std::thread t5(read_vals, values5);
go=true; go = true;
t5.join(); t5.join();
t4.join(); t4.join();
t3.join(); t3.join();
t2.join(); t2.join();
t1.join(); t1.join();
print(values1); print(values1);
print(values2); print(values2);
print(values3); print(values3);
print(values4); print(values4);
print(values5); print(values5);
} }

View File

@@ -1,46 +1,53 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<bool> x,y; std::atomic<bool> x, y;
std::atomic<int> z; std::atomic<int> z;
void write_x() void
write_x()
{ {
x.store(true,std::memory_order_release); x.store(true, std::memory_order_release);
} }
void write_y() void
write_y()
{ {
y.store(true,std::memory_order_release); y.store(true, std::memory_order_release);
} }
void read_x_then_y() void
read_x_then_y()
{ {
while(!x.load(std::memory_order_acquire)); while (!x.load(std::memory_order_acquire))
if(y.load(std::memory_order_acquire)) ;
++z; if (y.load(std::memory_order_acquire))
++z;
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_acquire)); while (!y.load(std::memory_order_acquire))
if(x.load(std::memory_order_acquire)) ;
++z; if (x.load(std::memory_order_acquire))
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x); std::thread a(write_x);
std::thread b(write_y); std::thread b(write_y);
std::thread c(read_x_then_y); std::thread c(read_x_then_y);
std::thread d(read_y_then_x); std::thread d(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
c.join(); c.join();
d.join(); d.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,31 +1,35 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<bool> x,y; std::atomic<bool> x, y;
std::atomic<int> z; std::atomic<int> z;
void write_x_then_y() void
write_x_then_y()
{ {
x.store(true,std::memory_order_relaxed); x.store(true, std::memory_order_relaxed);
y.store(true,std::memory_order_release); y.store(true, std::memory_order_release);
} }
void read_y_then_x() void
read_y_then_x()
{ {
while(!y.load(std::memory_order_acquire)); while (!y.load(std::memory_order_acquire))
if(x.load(std::memory_order_relaxed)) ;
++z; if (x.load(std::memory_order_relaxed))
++z;
} }
int main() int
main()
{ {
x=false; x = false;
y=false; y = false;
z=0; z = 0;
std::thread a(write_x_then_y); std::thread a(write_x_then_y);
std::thread b(read_y_then_x); std::thread b(read_y_then_x);
a.join(); a.join();
b.join(); b.join();
assert(z.load()!=0); assert(z.load() != 0);
} }

View File

@@ -1,42 +1,48 @@
#include <assert.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <assert.h>
std::atomic<int> data[5]; std::atomic<int> data[5];
std::atomic<bool> sync1(false),sync2(false); std::atomic<bool> sync1(false), sync2(false);
void thread_1() void
thread_1()
{ {
data[0].store(42,std::memory_order_relaxed); data[0].store(42, std::memory_order_relaxed);
data[1].store(97,std::memory_order_relaxed); data[1].store(97, std::memory_order_relaxed);
data[2].store(17,std::memory_order_relaxed); data[2].store(17, std::memory_order_relaxed);
data[3].store(-141,std::memory_order_relaxed); data[3].store(-141, std::memory_order_relaxed);
data[4].store(2003,std::memory_order_relaxed); data[4].store(2003, std::memory_order_relaxed);
sync1.store(true,std::memory_order_release); sync1.store(true, std::memory_order_release);
} }
void thread_2() void
thread_2()
{ {
while(!sync1.load(std::memory_order_acquire)); while (!sync1.load(std::memory_order_acquire))
sync2.store(std::memory_order_release); ;
sync2.store(std::memory_order_release);
} }
void thread_3() void
thread_3()
{ {
while(!sync2.load(std::memory_order_acquire)); while (!sync2.load(std::memory_order_acquire))
assert(data[0].load(std::memory_order_relaxed)==42); ;
assert(data[1].load(std::memory_order_relaxed)==97); assert(data[0].load(std::memory_order_relaxed) == 42);
assert(data[2].load(std::memory_order_relaxed)==17); assert(data[1].load(std::memory_order_relaxed) == 97);
assert(data[3].load(std::memory_order_relaxed)==-141); assert(data[2].load(std::memory_order_relaxed) == 17);
assert(data[4].load(std::memory_order_relaxed)==2003); assert(data[3].load(std::memory_order_relaxed) == -141);
assert(data[4].load(std::memory_order_relaxed) == 2003);
} }
int main() int
main()
{ {
std::thread t1(thread_1); std::thread t1(thread_1);
std::thread t2(thread_2); std::thread t2(thread_2);
std::thread t3(thread_3); std::thread t3(thread_3);
t1.join(); t1.join();
t2.join(); t2.join();
t3.join(); t3.join();
} }

View File

@@ -1,56 +1,52 @@
#include <exception> #include <exception>
#include <stack>
#include <mutex>
#include <memory> #include <memory>
#include <mutex>
#include <stack>
struct empty_stack: std::exception struct empty_stack : std::exception {
{ const char* what() const throw() { return "empty stack"; }
const char* what() const throw()
{
return "empty stack";
}
}; };
template<typename T> template <typename T>
class threadsafe_stack class threadsafe_stack {
{
private: private:
std::stack<T> data; std::stack<T> data;
mutable std::mutex m; mutable std::mutex m;
public: public:
threadsafe_stack(){} threadsafe_stack() {}
threadsafe_stack(const threadsafe_stack& other) threadsafe_stack(const threadsafe_stack& other)
{ {
std::lock_guard<std::mutex> lock(other.m); std::lock_guard<std::mutex> lock(other.m);
data=other.data; data = other.data;
} }
threadsafe_stack& operator=(const threadsafe_stack&) = delete; threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value) void push(T new_value)
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value)); data.push(std::move(new_value));
} }
std::shared_ptr<T> pop() std::shared_ptr<T> pop()
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack(); if (data.empty())
std::shared_ptr<T> const res( throw empty_stack();
std::make_shared<T>(std::move(data.top()))); std::shared_ptr<T> const res(std::make_shared<T>(std::move(data.top())));
data.pop(); data.pop();
return res; return res;
} }
void pop(T& value) void pop(T& value)
{ {
std::lock_guard<std::mutex> lock(m); std::lock_guard<std::mutex> lock(m);
if(data.empty()) throw empty_stack(); if (data.empty())
value=std::move(data.top()); throw empty_stack();
data.pop(); value = std::move(data.top());
} data.pop();
bool empty() const }
{ bool empty() const
std::lock_guard<std::mutex> lock(m); {
return data.empty(); std::lock_guard<std::mutex> lock(m);
} return data.empty();
}
}; };

View File

@@ -1,44 +1,41 @@
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
std::unique_ptr<node> try_pop_head() std::unique_ptr<node> try_pop_head()
{ {
std::lock_guard<std::mutex> head_lock(head_mutex); std::lock_guard<std::mutex> head_lock(head_mutex);
if(head.get()==get_tail()) if (head.get() == get_tail()) {
{ return std::unique_ptr<node>();
return std::unique_ptr<node>();
}
return pop_head();
} }
return pop_head();
}
std::unique_ptr<node> try_pop_head(T& value) std::unique_ptr<node> try_pop_head(T& value)
{ {
std::lock_guard<std::mutex> head_lock(head_mutex); std::lock_guard<std::mutex> head_lock(head_mutex);
if(head.get()==get_tail()) if (head.get() == get_tail()) {
{ return std::unique_ptr<node>();
return std::unique_ptr<node>();
}
value=std::move(*head->data);
return pop_head();
} }
value = std::move(*head->data);
return pop_head();
}
public: public:
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
std::unique_ptr<node> const old_head=try_pop_head(); std::unique_ptr<node> const old_head = try_pop_head();
return old_head?old_head->data:std::shared_ptr<T>(); return old_head ? old_head->data : std::shared_ptr<T>();
} }
bool try_pop(T& value) bool try_pop(T& value)
{ {
std::unique_ptr<node> const old_head=try_pop_head(value); std::unique_ptr<node> const old_head = try_pop_head(value);
return old_head; return old_head;
} }
void empty() void empty()
{ {
std::lock_guard<std::mutex> head_lock(head_mutex); std::lock_guard<std::mutex> head_lock(head_mutex);
return (head==get_tail()); return (head == get_tail());
} }
}; };

View File

@@ -1,108 +1,97 @@
#include <vector> #include <boost/thread/shared_mutex.hpp>
#include <memory>
#include <mutex>
#include <functional> #include <functional>
#include <list> #include <list>
#include <memory>
#include <mutex>
#include <utility> #include <utility>
#include <boost/thread/shared_mutex.hpp> #include <vector>
template<typename Key,typename Value,typename Hash=std::hash<Key> > template <typename Key, typename Value, typename Hash = std::hash<Key>>
class threadsafe_lookup_table class threadsafe_lookup_table {
{
private: private:
class bucket_type class bucket_type {
private:
typedef std::pair<Key, Value> bucket_value;
typedef std::list<bucket_value> bucket_data;
typedef typename bucket_data::iterator bucket_iterator;
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const
{ {
private: return std::find_if(
typedef std::pair<Key,Value> bucket_value; data.begin(), data.end(), [&](bucket_value const& item) {
typedef std::list<bucket_value> bucket_data; return item.first == key;
typedef typename bucket_data::iterator bucket_iterator; });
bucket_data data;
mutable boost::shared_mutex mutex;
bucket_iterator find_entry_for(Key const& key) const
{
return std::find_if(data.begin(),data.end(),
[&](bucket_value const& item)
{return item.first==key;});
}
public:
Value value_for(Key const& key,Value const& default_value) const
{
boost::shared_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
return (found_entry==data.end())?
default_value : found_entry->second;
}
void add_or_update_mapping(Key const& key,Value const& value)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
if(found_entry==data.end())
{
data.push_back(bucket_value(key,value));
}
else
{
found_entry->second=value;
}
}
void remove_mapping(Key const& key)
{
std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry=find_entry_for(key);
if(found_entry!=data.end())
{
data.erase(found_entry);
}
}
};
std::vector<std::unique_ptr<bucket_type> > buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
std::size_t const bucket_index=hasher(key)%buckets.size();
return *buckets[bucket_index];
} }
public: public:
typedef Key key_type; Value value_for(Key const& key, Value const& default_value) const
typedef Value mapped_type;
typedef Hash hash_type;
threadsafe_lookup_table(
unsigned num_buckets=19, Hash const& hasher_=Hash()):
buckets(num_buckets),hasher(hasher_)
{ {
for(unsigned i=0;i<num_buckets;++i) boost::shared_lock<boost::shared_mutex> lock(mutex);
{ bucket_iterator const found_entry = find_entry_for(key);
buckets[i].reset(new bucket_type); return (found_entry == data.end()) ? default_value : found_entry->second;
}
} }
threadsafe_lookup_table(threadsafe_lookup_table const& other)=delete; void add_or_update_mapping(Key const& key, Value const& value)
threadsafe_lookup_table& operator=(
threadsafe_lookup_table const& other)=delete;
Value value_for(Key const& key,
Value const& default_value=Value()) const
{ {
return get_bucket(key).value_for(key,default_value); std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry == data.end()) {
data.push_back(bucket_value(key, value));
}
else {
found_entry->second = value;
}
} }
void add_or_update_mapping(Key const& key,Value const& value)
{
get_bucket(key).add_or_update_mapping(key,value);
}
void remove_mapping(Key const& key) void remove_mapping(Key const& key)
{ {
get_bucket(key).remove_mapping(key); std::unique_lock<boost::shared_mutex> lock(mutex);
bucket_iterator const found_entry = find_entry_for(key);
if (found_entry != data.end()) {
data.erase(found_entry);
}
} }
};
std::vector<std::unique_ptr<bucket_type>> buckets;
Hash hasher;
bucket_type& get_bucket(Key const& key) const
{
std::size_t const bucket_index = hasher(key) % buckets.size();
return *buckets[bucket_index];
}
public:
typedef Key key_type;
typedef Value mapped_type;
typedef Hash hash_type;
threadsafe_lookup_table(unsigned num_buckets = 19,
Hash const& hasher_ = Hash())
: buckets(num_buckets), hasher(hasher_)
{
for (unsigned i = 0; i < num_buckets; ++i) {
buckets[i].reset(new bucket_type);
}
}
threadsafe_lookup_table(threadsafe_lookup_table const& other) = delete;
threadsafe_lookup_table& operator=(threadsafe_lookup_table const& other) =
delete;
Value value_for(Key const& key, Value const& default_value = Value()) const
{
return get_bucket(key).value_for(key, default_value);
}
void add_or_update_mapping(Key const& key, Value const& value)
{
get_bucket(key).add_or_update_mapping(key, value);
}
void remove_mapping(Key const& key) { get_bucket(key).remove_mapping(key); }
}; };

View File

@@ -1,20 +1,17 @@
std::map<Key,Value> threadsafe_lookup_table::get_map() const std::map<Key, Value>
threadsafe_lookup_table::get_map() const
{ {
std::vector<std::unique_lock<boost::shared_mutex> > locks; std::vector<std::unique_lock<boost::shared_mutex>> locks;
for(unsigned i=0;i<buckets.size();++i) for (unsigned i = 0; i < buckets.size(); ++i) {
{ locks.push_back(std::unique_lock<boost::shared_mutex>(buckets[i].mutex));
locks.push_back( }
std::unique_lock<boost::shared_mutex>(buckets[i].mutex)); std::map<Key, Value> res;
for (unsigned i = 0; i < buckets.size(); ++i) {
for (bucket_iterator it = buckets[i].data.begin();
it != buckets[i].data.end();
++it) {
res.insert(*it);
} }
std::map<Key,Value> res; }
for(unsigned i=0;i<buckets.size();++i) return res;
{
for(bucket_iterator it=buckets[i].data.begin();
it!=buckets[i].data.end();
++it)
{
res.insert(*it);
}
}
return res;
} }

View File

@@ -1,101 +1,87 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
template<typename T> template <typename T>
class threadsafe_list class threadsafe_list {
{ struct node {
struct node std::mutex m;
{ std::shared_ptr<T> data;
std::mutex m; std::unique_ptr<node> next;
std::shared_ptr<T> data;
std::unique_ptr<node> next;
node(): node() : next() {}
next()
{} node(T const& value) : data(std::make_shared<T>(value)) {}
};
node(T const& value):
data(std::make_shared<T>(value)) node head;
{}
};
node head;
public: public:
threadsafe_list() threadsafe_list() {}
{}
~threadsafe_list() ~threadsafe_list()
{ {
remove_if([](T const&){return true;}); remove_if([](T const&) { return true; });
} }
threadsafe_list(threadsafe_list const& other)=delete; threadsafe_list(threadsafe_list const& other) = delete;
threadsafe_list& operator=(threadsafe_list const& other)=delete; threadsafe_list& operator=(threadsafe_list const& other) = delete;
void push_front(T const& value)
{
std::unique_ptr<node> new_node(new node(value));
std::lock_guard<std::mutex> lk(head.m);
new_node->next=std::move(head.next);
head.next=std::move(new_node);
}
template<typename Function> void push_front(T const& value)
void for_each(Function f) {
{ std::unique_ptr<node> new_node(new node(value));
node* current=&head; std::lock_guard<std::mutex> lk(head.m);
std::unique_lock<std::mutex> lk(head.m); new_node->next = std::move(head.next);
while(node* const next=current->next.get()) head.next = std::move(new_node);
{ }
std::unique_lock<std::mutex> next_lk(next->m);
lk.unlock();
f(*next->data);
current=next;
lk=std::move(next_lk);
}
}
template<typename Predicate> template <typename Function>
std::shared_ptr<T> find_first_if(Predicate p) void for_each(Function f)
{ {
node* current=&head; node* current = &head;
std::unique_lock<std::mutex> lk(head.m); std::unique_lock<std::mutex> lk(head.m);
while(node* const next=current->next.get()) while (node* const next = current->next.get()) {
{ std::unique_lock<std::mutex> next_lk(next->m);
std::unique_lock<std::mutex> next_lk(next->m); lk.unlock();
lk.unlock(); f(*next->data);
if(p(*next->data)) current = next;
{ lk = std::move(next_lk);
return next->data;
}
current=next;
lk=std::move(next_lk);
}
return std::shared_ptr<T>();
} }
}
template<typename Predicate> template <typename Predicate>
void remove_if(Predicate p) std::shared_ptr<T> find_first_if(Predicate p)
{ {
node* current=&head; node* current = &head;
std::unique_lock<std::mutex> lk(head.m); std::unique_lock<std::mutex> lk(head.m);
while(node* const next=current->next.get()) while (node* const next = current->next.get()) {
{ std::unique_lock<std::mutex> next_lk(next->m);
std::unique_lock<std::mutex> next_lk(next->m); lk.unlock();
if(p(*next->data)) if (p(*next->data)) {
{ return next->data;
std::unique_ptr<node> old_next=std::move(current->next); }
current->next=std::move(next->next); current = next;
next_lk.unlock(); lk = std::move(next_lk);
}
else
{
lk.unlock();
current=next;
lk=std::move(next_lk);
}
}
} }
return std::shared_ptr<T>();
}
template <typename Predicate>
void remove_if(Predicate p)
{
node* current = &head;
std::unique_lock<std::mutex> lk(head.m);
while (node* const next = current->next.get()) {
std::unique_lock<std::mutex> next_lk(next->m);
if (p(*next->data)) {
std::unique_ptr<node> old_next = std::move(current->next);
current->next = std::move(next->next);
next_lk.unlock();
}
else {
lk.unlock();
current = next;
lk = std::move(next_lk);
}
}
}
}; };

View File

@@ -1,72 +1,70 @@
#include <queue>
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex>
#include <queue>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
mutable std::mutex mut; mutable std::mutex mut;
std::queue<T> data_queue; std::queue<T> data_queue;
std::condition_variable data_cond; std::condition_variable data_cond;
public: public:
threadsafe_queue() threadsafe_queue() {}
{}
void push(T new_value) void push(T new_value)
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
data_queue.push(std::move(new_value)); data_queue.push(std::move(new_value));
data_cond.notify_one(); data_cond.notify_one();
} }
void wait_and_pop(T& value) void wait_and_pop(T& value)
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
value=std::move(data_queue.front()); value = std::move(data_queue.front());
data_queue.pop(); data_queue.pop();
} }
std::shared_ptr<T> wait_and_pop() std::shared_ptr<T> wait_and_pop()
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
std::shared_ptr<T> res( std::shared_ptr<T> res(std::make_shared<T>(std::move(data_queue.front())));
std::make_shared<T>(std::move(data_queue.front()))); data_queue.pop();
data_queue.pop(); return res;
return res; }
}
bool try_pop(T& value) bool try_pop(T& value)
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty()) if (data_queue.empty())
return false; return false;
value=std::move(data_queue.front()); value = std::move(data_queue.front());
data_queue.pop(); data_queue.pop();
} }
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty()) if (data_queue.empty())
return std::shared_ptr<T>(); return std::shared_ptr<T>();
std::shared_ptr<T> res( std::shared_ptr<T> res(std::make_shared<T>(std::move(data_queue.front())));
std::make_shared<T>(std::move(data_queue.front()))); data_queue.pop();
data_queue.pop(); return res;
return res; }
}
bool empty() const bool empty() const
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
return data_queue.empty(); return data_queue.empty();
} }
}; };
int main() int
main()
{ {
threadsafe_queue<int> rq; threadsafe_queue<int> rq;
} }

View File

@@ -1,68 +1,65 @@
#include <queue>
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <memory> #include <memory>
#include <mutex>
#include <queue>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
mutable std::mutex mut; mutable std::mutex mut;
std::queue<std::shared_ptr<T> > data_queue; std::queue<std::shared_ptr<T>> data_queue;
std::condition_variable data_cond; std::condition_variable data_cond;
public: public:
threadsafe_queue() threadsafe_queue() {}
{}
void wait_and_pop(T& value) void wait_and_pop(T& value)
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
value=std::move(*data_queue.front()); value = std::move(*data_queue.front());
data_queue.pop(); data_queue.pop();
} }
bool try_pop(T& value) bool try_pop(T& value)
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty()) if (data_queue.empty())
return false; return false;
value=std::move(*data_queue.front()); value = std::move(*data_queue.front());
data_queue.pop(); data_queue.pop();
} }
std::shared_ptr<T> wait_and_pop() std::shared_ptr<T> wait_and_pop()
{ {
std::unique_lock<std::mutex> lk(mut); std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[this]{return !data_queue.empty();}); data_cond.wait(lk, [this] { return !data_queue.empty(); });
std::shared_ptr<T> res=data_queue.front(); std::shared_ptr<T> res = data_queue.front();
data_queue.pop(); data_queue.pop();
return res; return res;
} }
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
if(data_queue.empty()) if (data_queue.empty())
return std::shared_ptr<T>(); return std::shared_ptr<T>();
std::shared_ptr<T> res=data_queue.front(); std::shared_ptr<T> res = data_queue.front();
data_queue.pop(); data_queue.pop();
return res; return res;
} }
bool empty() const bool empty() const
{ {
std::lock_guard<std::mutex> lk(mut); std::lock_guard<std::mutex> lk(mut);
return data_queue.empty(); return data_queue.empty();
} }
void push(T new_value)
{
std::shared_ptr<T> data(
std::make_shared<T>(std::move(new_value)));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
void push(T new_value)
{
std::shared_ptr<T> data(std::make_shared<T>(std::move(new_value)));
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one();
}
}; };

View File

@@ -1,56 +1,45 @@
#include <memory> #include <memory>
template<typename T> template <typename T>
class queue class queue {
{
private: private:
struct node struct node {
{ T data;
T data; std::unique_ptr<node> next;
std::unique_ptr<node> next;
node(T data_) : data(std::move(data_)) {}
};
std::unique_ptr<node> head;
node* tail;
node(T data_):
data(std::move(data_))
{}
};
std::unique_ptr<node> head;
node* tail;
public: public:
queue(): queue() : tail(nullptr) {}
tail(nullptr)
{}
queue(const queue& other)=delete; queue(const queue& other) = delete;
queue& operator=(const queue& other)=delete; queue& operator=(const queue& other) = delete;
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
if(!head) if (!head) {
{ return std::shared_ptr<T>();
return std::shared_ptr<T>();
}
std::shared_ptr<T> const res(
std::make_shared<T>(std::move(head->data)));
std::unique_ptr<node> const old_head=std::move(head);
head=std::move(old_head->next);
return res;
} }
std::shared_ptr<T> const res(std::make_shared<T>(std::move(head->data)));
void push(T new_value) std::unique_ptr<node> const old_head = std::move(head);
{ head = std::move(old_head->next);
std::unique_ptr<node> p(new node(std::move(new_value))); return res;
node* const new_tail=p.get(); }
if(tail)
{ void push(T new_value)
tail->next=std::move(p); {
} std::unique_ptr<node> p(new node(std::move(new_value)));
else node* const new_tail = p.get();
{ if (tail) {
head=std::move(p); tail->next = std::move(p);
}
tail=new_tail;
} }
else {
head = std::move(p);
}
tail = new_tail;
}
}; };

View File

@@ -1,46 +1,39 @@
#include <memory> #include <memory>
template<typename T> template <typename T>
class queue class queue {
{
private: private:
struct node struct node {
{ std::shared_ptr<T> data;
std::shared_ptr<T> data; std::unique_ptr<node> next;
std::unique_ptr<node> next; };
};
std::unique_ptr<node> head;
std::unique_ptr<node> head; node* tail;
node* tail;
public: public:
queue(): queue() : head(new node), tail(head.get()) {}
head(new node),tail(head.get())
{}
queue(const queue& other)=delete; queue(const queue& other) = delete;
queue& operator=(const queue& other)=delete; queue& operator=(const queue& other) = delete;
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
if(head.get()==tail) if (head.get() == tail) {
{ return std::shared_ptr<T>();
return std::shared_ptr<T>();
}
std::shared_ptr<T> const res(head->data);
std::unique_ptr<node> const old_head=std::move(head);
head=std::move(old_head->next);
return res;
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
tail->data=new_data;
node* const new_tail=p.get();
tail->next=std::move(p);
tail=new_tail;
} }
std::shared_ptr<T> const res(head->data);
std::unique_ptr<node> const old_head = std::move(head);
head = std::move(old_head->next);
return res;
}
void push(T new_value)
{
std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
tail->data = new_data;
node* const new_tail = p.get();
tail->next = std::move(p);
tail = new_tail;
}
}; };

View File

@@ -1,64 +1,56 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
struct node struct node {
{ std::shared_ptr<T> data;
std::shared_ptr<T> data; std::unique_ptr<node> next;
std::unique_ptr<node> next; };
};
std::mutex head_mutex;
std::unique_ptr<node> head;
std::mutex tail_mutex;
node* tail;
node* get_tail()
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail;
}
std::unique_ptr<node> pop_head() std::mutex head_mutex;
{ std::unique_ptr<node> head;
std::lock_guard<std::mutex> head_lock(head_mutex); std::mutex tail_mutex;
if(head.get()==get_tail()) node* tail;
{
return nullptr; node* get_tail()
} {
std::unique_ptr<node> const old_head=std::move(head); std::lock_guard<std::mutex> tail_lock(tail_mutex);
head=std::move(old_head->next); return tail;
return old_head; }
std::unique_ptr<node> pop_head()
{
std::lock_guard<std::mutex> head_lock(head_mutex);
if (head.get() == get_tail()) {
return nullptr;
} }
std::unique_ptr<node> const old_head = std::move(head);
head = std::move(old_head->next);
return old_head;
}
public: public:
threadsafe_queue(): threadsafe_queue() : head(new node), tail(head.get()) {}
head(new node),tail(head.get())
{}
threadsafe_queue(const threadsafe_queue& other)=delete; threadsafe_queue(const threadsafe_queue& other) = delete;
threadsafe_queue& operator=(const threadsafe_queue& other)=delete; threadsafe_queue& operator=(const threadsafe_queue& other) = delete;
std::shared_ptr<T> try_pop() std::shared_ptr<T> try_pop()
{ {
std::unique_ptr<node> old_head=pop_head(); std::unique_ptr<node> old_head = pop_head();
return old_head?old_head->data:std::shared_ptr<T>(); return old_head ? old_head->data : std::shared_ptr<T>();
} }
void push(T new_value) void push(T new_value)
{ {
std::shared_ptr<T> new_data( std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
std::make_shared<T>(std::move(new_value))); std::unique_ptr<node> p(new node);
std::unique_ptr<node> p(new node); node* const new_tail = p.get();
node* const new_tail=p.get(); std::lock_guard<std::mutex> tail_lock(tail_mutex);
std::lock_guard<std::mutex> tail_lock(tail_mutex); tail->data = new_data;
tail->data=new_data; tail->next = std::move(p);
tail->next=std::move(p); tail = new_tail;
tail=new_tail; }
}
}; };

View File

@@ -1,29 +1,26 @@
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
struct node struct node {
{ std::shared_ptr<T> data;
std::shared_ptr<T> data; std::unique_ptr<node> next;
std::unique_ptr<node> next; };
};
std::mutex head_mutex;
std::unique_ptr<node> head;
std::mutex tail_mutex;
node* tail;
std::condition_variable data_cond;
public:
threadsafe_queue():
head(new node),tail(head.get())
{}
threadsafe_queue(const threadsafe_queue& other)=delete;
threadsafe_queue& operator=(const threadsafe_queue& other)=delete;
std::shared_ptr<T> try_pop(); std::mutex head_mutex;
bool try_pop(T& value); std::unique_ptr<node> head;
std::shared_ptr<T> wait_and_pop(); std::mutex tail_mutex;
void wait_and_pop(T& value); node* tail;
void push(T new_value); std::condition_variable data_cond;
void empty();
public:
threadsafe_queue() : head(new node), tail(head.get()) {}
threadsafe_queue(const threadsafe_queue& other) = delete;
threadsafe_queue& operator=(const threadsafe_queue& other) = delete;
std::shared_ptr<T> try_pop();
bool try_pop(T& value);
std::shared_ptr<T> wait_and_pop();
void wait_and_pop(T& value);
void push(T new_value);
void empty();
}; };

View File

@@ -1,15 +1,15 @@
template<typename T> template <typename T>
void threadsafe_queue<T>::push(T new_value) void
threadsafe_queue<T>::push(T new_value)
{ {
std::shared_ptr<T> new_data( std::shared_ptr<T> new_data(std::make_shared<T>(std::move(new_value)));
std::make_shared<T>(std::move(new_value))); std::unique_ptr<node> p(new node);
std::unique_ptr<node> p(new node); {
{ std::lock_guard<std::mutex> tail_lock(tail_mutex);
std::lock_guard<std::mutex> tail_lock(tail_mutex); tail->data = new_data;
tail->data=new_data; node* const new_tail = p.get();
node* const new_tail=p.get(); tail->next = std::move(p);
tail->next=std::move(p); tail = new_tail;
tail=new_tail; }
} data_cond.notify_one();
data_cond.notify_one();
} }

View File

@@ -1,49 +1,48 @@
template<typename T> template <typename T>
class threadsafe_queue class threadsafe_queue {
{
private: private:
node* get_tail() node* get_tail()
{ {
std::lock_guard<std::mutex> tail_lock(tail_mutex); std::lock_guard<std::mutex> tail_lock(tail_mutex);
return tail; return tail;
} }
std::unique_ptr<node> pop_head() std::unique_ptr<node> pop_head()
{ {
std::unique_ptr<node> const old_head=std::move(head); std::unique_ptr<node> const old_head = std::move(head);
head=std::move(old_head->next); head = std::move(old_head->next);
return old_head; return old_head;
} }
std::unique_lock<std::mutex> wait_for_data() std::unique_lock<std::mutex> wait_for_data()
{ {
std::unique_lock<std::mutex> head_lock(head_mutex); std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock,[&]{return head!=get_tail();}); data_cond.wait(head_lock, [&] { return head != get_tail(); });
return std::move(head_lock); return std::move(head_lock);
} }
std::unique_ptr<node> wait_pop_head() std::unique_ptr<node> wait_pop_head()
{ {
std::unique_lock<std::mutex> head_lock(wait_for_data()); std::unique_lock<std::mutex> head_lock(wait_for_data());
return pop_head(); return pop_head();
} }
std::unique_ptr<node> wait_pop_head(T& value)
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
value = std::move(*head->data);
return pop_head();
}
std::unique_ptr<node> wait_pop_head(T& value)
{
std::unique_lock<std::mutex> head_lock(wait_for_data());
value=std::move(*head->data);
return pop_head();
}
public: public:
std::shared_ptr<T> wait_and_pop() std::shared_ptr<T> wait_and_pop()
{ {
std::unique_ptr<node> const old_head=wait_pop_head(); std::unique_ptr<node> const old_head = wait_pop_head();
return old_head->data; return old_head->data;
} }
void wait_and_pop(T& value) void wait_and_pop(T& value)
{ {
std::unique_ptr<node> const old_head=wait_pop_head(value); std::unique_ptr<node> const old_head = wait_pop_head(value);
} }
}; };

View File

@@ -1,18 +1,14 @@
#include <atomic> #include <atomic>
class spinlock_mutex class spinlock_mutex {
{ std::atomic_flag flag;
std::atomic_flag flag;
public: public:
spinlock_mutex(): spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {}
flag(ATOMIC_FLAG_INIT) void lock()
{} {
void lock() while (flag.test_and_set(std::memory_order_acquire))
{ ;
while(flag.test_and_set(std::memory_order_acquire)); }
} void unlock() { flag.clear(std::memory_order_release); }
void unlock()
{
flag.clear(std::memory_order_release);
}
}; };

View File

@@ -1,38 +1,37 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
template<typename T> template <typename T>
class lock_free_stack class lock_free_stack {
{
private: private:
struct node; struct node;
struct counted_node_ptr struct counted_node_ptr {
int external_count;
node* ptr;
};
struct node {
std::shared_ptr<T> data;
std::atomic<int> internal_count;
counted_node_ptr next;
node(T const& data_) : data(std::make_shared<T>(data_)), internal_count(0)
{ {
int external_count; }
node* ptr; };
}; std::atomic<counted_node_ptr> head;
struct node
{
std::shared_ptr<T> data;
std::atomic<int> internal_count;
counted_node_ptr next;
node(T const& data_):
data(std::make_shared<T>(data_)),
internal_count(0)
{}
};
std::atomic<counted_node_ptr> head;
public: public:
~lock_free_stack() ~lock_free_stack()
{ {
while(pop()); while (pop())
} ;
void push(T const& data) }
{ void push(T const& data)
counted_node_ptr new_node; {
new_node.ptr=new node(data); counted_node_ptr new_node;
new_node.external_count=1; new_node.ptr = new node(data);
new_node.ptr->next=head.load(); new_node.external_count = 1;
while(!head.compare_exchange_weak(new_node.ptr->next,new_node)); new_node.ptr->next = head.load();
} while (!head.compare_exchange_weak(new_node.ptr->next, new_node))
;
}
}; };

View File

@@ -1,46 +1,38 @@
template<typename T> template <typename T>
class lock_free_stack class lock_free_stack {
{
private: private:
void increase_head_count(counted_node_ptr& old_counter) void increase_head_count(counted_node_ptr& old_counter)
{ {
counted_node_ptr new_counter; counted_node_ptr new_counter;
do do {
{ new_counter = old_counter;
new_counter=old_counter; ++new_counter.external_count;
++new_counter.external_count; } while (!head.compare_exchange_strong(old_counter, new_counter));
} old_counter.external_count = new_counter.external_count;
while(!head.compare_exchange_strong(old_counter,new_counter)); }
old_counter.external_count=new_counter.external_count;
}
public: public:
std::shared_ptr<T> pop() std::shared_ptr<T> pop()
{ {
counted_node_ptr old_head=head.load(); counted_node_ptr old_head = head.load();
for(;;) for (;;) {
{ increase_head_count(old_head);
increase_head_count(old_head); node* const ptr = old_head.ptr;
node* const ptr=old_head.ptr; if (!ptr) {
if(!ptr) return std::shared_ptr<T>();
{ }
return std::shared_ptr<T>(); if (head.compare_exchange_strong(old_head, ptr->next)) {
} std::shared_ptr<T> res;
if(head.compare_exchange_strong(old_head,ptr->next)) res.swap(ptr->data);
{ int const count_increase = old_head.external_count - 2;
std::shared_ptr<T> res; if (ptr->internal_count.fetch_add(count_increase) == -count_increase) {
res.swap(ptr->data); delete ptr;
int const count_increase=old_head.external_count-2;
if(ptr->internal_count.fetch_add(count_increase)==
-count_increase)
{
delete ptr;
}
return res;
}
else if(ptr->internal_count.fetch_sub(1)==1)
{
delete ptr;
}
} }
return res;
}
else if (ptr->internal_count.fetch_sub(1) == 1) {
delete ptr;
}
} }
}
}; };

View File

@@ -1,88 +1,78 @@
#include <atomic> #include <atomic>
#include <memory> #include <memory>
template<typename T> template <typename T>
class lock_free_stack class lock_free_stack {
{
private: private:
struct node; struct node;
struct counted_node_ptr struct counted_node_ptr {
int external_count;
node* ptr;
};
struct node {
std::shared_ptr<T> data;
std::atomic<int> internal_count;
counted_node_ptr next;
node(T const& data_) : data(std::make_shared<T>(data_)), internal_count(0)
{ {
int external_count;
node* ptr;
};
struct node
{
std::shared_ptr<T> data;
std::atomic<int> internal_count;
counted_node_ptr next;
node(T const& data_):
data(std::make_shared<T>(data_)),
internal_count(0)
{}
};
std::atomic<counted_node_ptr> head;
void increase_head_count(counted_node_ptr& old_counter)
{
counted_node_ptr new_counter;
do
{
new_counter=old_counter;
++new_counter.external_count;
}
while(!head.compare_exchange_strong(
old_counter,new_counter,
std::memory_order_acquire,
std::memory_order_relaxed));
old_counter.external_count=new_counter.external_count;
} }
};
std::atomic<counted_node_ptr> head;
void increase_head_count(counted_node_ptr& old_counter)
{
counted_node_ptr new_counter;
do {
new_counter = old_counter;
++new_counter.external_count;
} while (!head.compare_exchange_strong(old_counter,
new_counter,
std::memory_order_acquire,
std::memory_order_relaxed));
old_counter.external_count = new_counter.external_count;
}
public: public:
~lock_free_stack() ~lock_free_stack()
{ {
while(pop()); while (pop())
} ;
void push(T const& data) }
{ void push(T const& data)
counted_node_ptr new_node; {
new_node.ptr=new node(data); counted_node_ptr new_node;
new_node.external_count=1; new_node.ptr = new node(data);
new_node.ptr->next=head.load(std::memory_order_relaxed) new_node.external_count = 1;
while(!head.compare_exchange_weak( new_node.ptr->next = head.load(std::memory_order_relaxed) while (
new_node.ptr->next,new_node, !head.compare_exchange_weak(new_node.ptr->next,
std::memory_order_release, new_node,
std::memory_order_relaxed)); std::memory_order_release,
} std::memory_order_relaxed));
std::shared_ptr<T> pop() }
{ std::shared_ptr<T> pop()
counted_node_ptr old_head= {
head.load(std::memory_order_relaxed); counted_node_ptr old_head = head.load(std::memory_order_relaxed);
for(;;) for (;;) {
{ increase_head_count(old_head);
increase_head_count(old_head); node* const ptr = old_head.ptr;
node* const ptr=old_head.ptr; if (!ptr) {
if(!ptr) return std::shared_ptr<T>();
{ }
return std::shared_ptr<T>(); if (head.compare_exchange_strong(
} old_head, ptr->next, std::memory_order_relaxed)) {
if(head.compare_exchange_strong( std::shared_ptr<T> res;
old_head,ptr->next,std::memory_order_relaxed)) res.swap(ptr->data);
{ int const count_increase = old_head.external_count - 2;
std::shared_ptr<T> res; if (ptr->internal_count.fetch_add(
res.swap(ptr->data); count_increase, std::memory_order_release) == -count_increase) {
int const count_increase=old_head.external_count-2; delete ptr;
if(ptr->internal_count.fetch_add(
count_increase,std::memory_order_release)==-count_increase)
{
delete ptr;
}
return res;
}
else if(ptr->internal_count.fetch_add(
-1,std::memory_order_relaxed)==1)
{
ptr->internal_count.load(std::memory_order_acquire);
delete ptr;
}
} }
return res;
}
else if (ptr->internal_count.fetch_add(-1, std::memory_order_relaxed) ==
1) {
ptr->internal_count.load(std::memory_order_acquire);
delete ptr;
}
} }
}
}; };

View File

@@ -1,62 +1,54 @@
#include <memory>
#include <atomic> #include <atomic>
#include <memory>
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
struct node struct node {
{ std::shared_ptr<T> data;
std::shared_ptr<T> data; node* next;
node* next; node() : next(nullptr) {}
node(): };
next(nullptr) std::atomic<node*> head;
{} std::atomic<node*> tail;
}; node* pop_head()
std::atomic<node*> head; {
std::atomic<node*> tail; node* const old_head = head.load();
node* pop_head() if (old_head == tail.load()) {
{ return nullptr;
node* const old_head=head.load();
if(old_head==tail.load())
{
return nullptr;
}
head.store(old_head->next);
return old_head;
} }
head.store(old_head->next);
return old_head;
}
public: public:
lock_free_queue(): lock_free_queue() : head(new node), tail(head.load()) {}
head(new node),tail(head.load()) lock_free_queue(const lock_free_queue& other) = delete;
{} lock_free_queue& operator=(const lock_free_queue& other) = delete;
lock_free_queue(const lock_free_queue& other)=delete; ~lock_free_queue()
lock_free_queue& operator=(const lock_free_queue& other)=delete; {
~lock_free_queue() while (node* const old_head = head.load()) {
{ head.store(old_head->next);
while(node* const old_head=head.load()) delete old_head;
{
head.store(old_head->next);
delete old_head;
}
} }
std::shared_ptr<T> pop() }
{ std::shared_ptr<T> pop()
node* old_head=pop_head(); {
if(!old_head) node* old_head = pop_head();
{ if (!old_head) {
return std::shared_ptr<T>(); return std::shared_ptr<T>();
}
std::shared_ptr<T> const res(old_head->data);
delete old_head;
return res;
}
void push(T new_value)
{
std::shared_ptr<T> new_data(std::make_shared<T>(new_value));
node* p=new node;
node* const old_tail=tail.load();
old_tail->data.swap(new_data);
old_tail->next=p;
tail.store(p);
} }
std::shared_ptr<T> const res(old_head->data);
delete old_head;
return res;
}
void push(T new_value)
{
std::shared_ptr<T> new_data(std::make_shared<T>(new_value));
node* p = new node;
node* const old_tail = tail.load();
old_tail->data.swap(new_data);
old_tail->next = p;
tail.store(p);
}
}; };

View File

@@ -1,20 +1,18 @@
void push(T new_value) void
push(T new_value)
{ {
std::unique_ptr<T> new_data(new T(new_value)); std::unique_ptr<T> new_data(new T(new_value));
counted_node_ptr new_next; counted_node_ptr new_next;
new_next.ptr=new node; new_next.ptr = new node;
new_next.external_count=1; new_next.external_count = 1;
for(;;) for (;;) {
{ node* const old_tail = tail.load();
node* const old_tail=tail.load(); T* old_data = nullptr;
T* old_data=nullptr; if (old_tail->data.compare_exchange_strong(old_data, new_data.get())) {
if(old_tail->data.compare_exchange_strong( old_tail->next = new_next;
old_data,new_data.get())) tail.store(new_next.ptr);
{ new_data.release();
old_tail->next=new_next; break;
tail.store(new_next.ptr);
new_data.release();
break;
}
} }
}
} }

View File

@@ -1,59 +1,54 @@
#include <atomic> #include <atomic>
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
struct node; struct node;
struct counted_node_ptr struct counted_node_ptr {
int external_count;
node* ptr;
};
std::atomic<counted_node_ptr> head;
std::atomic<counted_node_ptr> tail;
struct node_counter {
unsigned internal_count : 30;
unsigned external_counters : 2;
};
struct node {
std::atomic<T*> data;
std::atomic<node_counter> count;
counted_node_ptr next;
node()
{ {
int external_count; node_counter new_count;
node* ptr; new_count.internal_count = 0;
}; new_count.external_counters = 2;
std::atomic<counted_node_ptr> head; count.store(new_count);
std::atomic<counted_node_ptr> tail; next.ptr = nullptr;
struct node_counter next.external_count = 0;
{
unsigned internal_count:30;
unsigned external_counters:2;
};
struct node
{
std::atomic<T*> data;
std::atomic<node_counter> count;
counted_node_ptr next;
node()
{
node_counter new_count;
new_count.internal_count=0;
new_count.external_counters=2;
count.store(new_count);
next.ptr=nullptr;
next.external_count=0;
}
};
public:
void push(T new_value)
{
std::unique_ptr<T> new_data(new T(new_value));
counted_node_ptr new_next;
new_next.ptr=new node;
new_next.external_count=1;
counted_node_ptr old_tail=tail.load();
for(;;)
{
increase_external_count(tail,old_tail);
T* old_data=nullptr;
if(old_tail.ptr->data.compare_exchange_strong(
old_data,new_data.get()))
{
old_tail.ptr->next=new_next;
old_tail=tail.exchange(new_next);
free_external_counter(old_tail);
new_data.release();
break;
}
old_tail.ptr->release_ref();
}
} }
};
public:
void push(T new_value)
{
std::unique_ptr<T> new_data(new T(new_value));
counted_node_ptr new_next;
new_next.ptr = new node;
new_next.external_count = 1;
counted_node_ptr old_tail = tail.load();
for (;;) {
increase_external_count(tail, old_tail);
T* old_data = nullptr;
if (old_tail.ptr->data.compare_exchange_strong(old_data,
new_data.get())) {
old_tail.ptr->next = new_next;
old_tail = tail.exchange(new_next);
free_external_counter(old_tail);
new_data.release();
break;
}
old_tail.ptr->release_ref();
}
}
}; };

View File

@@ -1,31 +1,27 @@
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
struct node struct node {
{ void release_ref();
void release_ref(); };
};
public: public:
std::unique_ptr<T> pop() std::unique_ptr<T> pop()
{ {
counted_node_ptr old_head=head.load(std::memory_order_relaxed); counted_node_ptr old_head = head.load(std::memory_order_relaxed);
for(;;) for (;;) {
{ increase_external_count(head, old_head);
increase_external_count(head,old_head); node* const ptr = old_head.ptr;
node* const ptr=old_head.ptr; if (ptr == tail.load().ptr) {
if(ptr==tail.load().ptr) ptr->release_ref();
{ return std::unique_ptr<T>();
ptr->release_ref(); }
return std::unique_ptr<T>(); if (head.compare_exchange_strong(old_head, ptr->next)) {
} T* const res = ptr->data.exchange(nullptr);
if(head.compare_exchange_strong(old_head,ptr->next)) free_external_counter(old_head);
{ return std::unique_ptr<T>(res);
T* const res=ptr->data.exchange(nullptr); }
free_external_counter(old_head); ptr->release_ref();
return std::unique_ptr<T>(res);
}
ptr->release_ref();
}
} }
}
}; };

View File

@@ -1,27 +1,21 @@
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
struct node struct node {
void release_ref()
{ {
void release_ref() node_counter old_counter = count.load(std::memory_order_relaxed);
{ node_counter new_counter;
node_counter old_counter= do {
count.load(std::memory_order_relaxed); new_counter = old_counter;
node_counter new_counter; --new_counter.internal_count;
do } while (!count.compare_exchange_strong(old_counter,
{ new_counter,
new_counter=old_counter; std::memory_order_acquire,
--new_counter.internal_count; std::memory_order_relaxed));
} if (!new_counter.internal_count && !new_counter.external_counters) {
while(!count.compare_exchange_strong( delete this;
old_counter,new_counter, }
std::memory_order_acquire,std::memory_order_relaxed)); }
if(!new_counter.internal_count && };
!new_counter.external_counters)
{
delete this;
}
}
};
}; };

View File

@@ -1,20 +1,17 @@
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
static void increase_external_count( static void increase_external_count(std::atomic<counted_node_ptr>& counter,
std::atomic<counted_node_ptr>& counter, counted_node_ptr& old_counter)
counted_node_ptr& old_counter) {
{ counted_node_ptr new_counter;
counted_node_ptr new_counter; do {
do new_counter = old_counter;
{ ++new_counter.external_count;
new_counter=old_counter; } while (!counter.compare_exchange_strong(old_counter,
++new_counter.external_count; new_counter,
} std::memory_order_acquire,
while(!counter.compare_exchange_strong( std::memory_order_relaxed));
old_counter,new_counter, old_counter.external_count = new_counter.external_count;
std::memory_order_acquire,std::memory_order_relaxed)); }
old_counter.external_count=new_counter.external_count;
}
}; };

View File

@@ -1,27 +1,22 @@
template<typename T> template <typename T>
class lock_free_queue class lock_free_queue {
{
private: private:
static void free_external_counter(counted_node_ptr &old_node_ptr) static void free_external_counter(counted_node_ptr& old_node_ptr)
{ {
node* const ptr=old_node_ptr.ptr; node* const ptr = old_node_ptr.ptr;
int const count_increase=old_node_ptr.external_count-2; int const count_increase = old_node_ptr.external_count - 2;
node_counter old_counter= node_counter old_counter = ptr->count.load(std::memory_order_relaxed);
ptr->count.load(std::memory_order_relaxed); node_counter new_counter;
node_counter new_counter; do {
do new_counter = old_counter;
{ --new_counter.external_counters;
new_counter=old_counter; new_counter.internal_count += count_increase;
--new_counter.external_counters; } while (!ptr->count.compare_exchange_strong(old_counter,
new_counter.internal_count+=count_increase; new_counter,
} std::memory_order_acquire,
while(!ptr->count.compare_exchange_strong( std::memory_order_relaxed));
old_counter,new_counter, if (!new_counter.internal_count && !new_counter.external_counters) {
std::memory_order_acquire,std::memory_order_relaxed)); delete ptr;
if(!new_counter.internal_count &&
!new_counter.external_counters)
{
delete ptr;
}
} }
}
}; };

View File

@@ -1,23 +1,21 @@
#include <atomic> #include <atomic>
template<typename T> template <typename T>
class lock_free_stack class lock_free_stack {
{
private: private:
struct node struct node {
{ T data;
T data; node* next;
node* next; node(T const& data_) : data(data_) {}
node(T const& data_): };
data(data_) std::atomic<node*> head;
{}
};
std::atomic<node*> head;
public: public:
void push(T const& data) void push(T const& data)
{ {
node* const new_node=new node(data); node* const new_node = new node(data);
new_node->next=head.load(); new_node->next = head.load();
while(!head.compare_exchange_weak(new_node->next,new_node)); while (!head.compare_exchange_weak(new_node->next, new_node))
} ;
}
}; };

Some files were not shown because too many files have changed in this diff Show More