美文网首页
一个简单的线程安全的stack

一个简单的线程安全的stack

作者: FredricZhu | 来源:发表于2023-10-24 11:37 被阅读0次

本例的stack在接口设计上和std::stack略有不同,是std::stack的一个基于std::mutex的简单封装。
本例合并了top和pop接口统一到pop,因为在top和pop之间如果有其他操作,无法纳入std::mutex管辖之内,只能勉强将其合并。
程序代码如下,
conanfile.txt

[requires]
boost/1.72.0

[generators]
cmake

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)

project(3_5_thread_safe_stack)

set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig/")

set ( CMAKE_CXX_FLAGS "-pthread")
set(CMAKE_CXX_STANDARD 17)
add_definitions(-g)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

include_directories(${INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRS})

file( GLOB main_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 

foreach( main_file ${main_file_list} )
    file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${main_file})
    string(REPLACE ".cpp" "" file ${filename})
    add_executable(${file}  ${main_file})
    target_link_libraries(${file} ${CONAN_LIBS} pthread)
endforeach( main_file ${main_file_list})

main.cpp

#include <iostream>
#include <mutex>
#include <algorithm>
#include <functional>
#include <thread>
#include <stack>
#include <memory>
#include <exception>

struct empty_stack: public std::exception {
    char const* what() const noexcept {
        return "empty stack";
    }
};

template <typename T>
class threadsafe_stack {
private:
    std::stack<T> data;
    mutable std::mutex m;

public:
    threadsafe_stack() {}
    threadsafe_stack(threadsafe_stack const& other) {
        std::lock_guard<std::mutex> lock(other.m);
        data = other.data;
    }
    // 不允许拷贝赋值
    threadsafe_stack& operator=(threadsafe_stack const&) = delete;

    void push(T new_value) {
        std::lock_guard<std::mutex> lock(m);
        data.push(new_value);
    } 

    std::shared_ptr<T> pop() {
        std::lock_guard<std::mutex> lock(m);
        if(data.empty()) {
            throw empty_stack();
        }

        std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
        data.pop();
        return res;
    }

    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 argc, char* argv[]) {
    threadsafe_stack<int> si;
    std::thread add_thread([&]() {
        for(int i=0; i<10000; ++i) {
            si.push(i);
        }
    });
    
    std::thread pop_thread([&]() {
        for(int i=0; i<10000; ++i) {
            if(!si.empty()) {
                std::cout << *(si.pop()) << std::endl;
            }
        }
    });

    add_thread.join();
    pop_thread.join();

    return EXIT_SUCCESS;
}

多线程操作后,并不能保证栈上10000个元素都先进后出,因为pop没有等到push完就开始操作了。但是threadsafe_stack能够保证数据整整是10000个,不会有重复的,错误的数据。
如果等到10000个元素都push完,就没有threadsafe的意义了,就是单线程操作了。

相关文章

  • Stack源代码分析

    Stack是栈,特点是FILO(先进先出),Stack继承了Vector stack中的方法是线程安全的,比如ad...

  • HashMap和HashTable的区别

    java.util包下提供了部分线程安全的类,有Vector、Stack、HashTable、Enumeratio...

  • Util.Stack(线程安全)

    继承于util.Vector,以数组形式实现栈 初始化容量是10,每次扩容增大一倍若仍无法满足最小需求容量,将设为...

  • 并发编程

    1、什么是线程安全,怎么保证线程安全? 线程安全可以简单理解为一个方法或者一个实例可以在多线程环境中使用而不会出现...

  • 栈与栈的应用

    一、阅读源码,得知,stack类继承自Vector,而Vector相当于线程安全的arraylist(相反的arr...

  • 进程与线程、线程池

    进程与线程的相关总结进程与线程的简单解释进程: 基本的资源分配资源线程: 最小调度单元 线程安全 线程安全是多线程...

  • 多线程(Pthread/NSThread)

    Pthread简单使用 NSThread基本使用 线程的状态 线程的安全 线程间通讯

  • 单例设计模式

    饿汉式,线程安全 但效率比较低 饱汉式,非线程安全 饱汉式,线程安全简单实现 线程安全 并且效率高 单例模式最优...

  • jvm栈和堆(小白入门文,各博客精要合集)

    java的栈1.当一个新的线程创建时,JVM会为这个线程创建一个新的Stack。一个Java Stack在一个个独...

  • Java 虚拟机简介

    1.整体框架 2.每一个线程对应一个VM Stack,线程执行就是方法压栈出栈的过程,压入VM Stack里面的每...

网友评论

      本文标题:一个简单的线程安全的stack

      本文链接:https://www.haomeiwen.com/subject/sklsidtx.html