一个简单的线程安全的stack

2023-10-24  本文已影响0人  FredricZhu

本例的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的意义了,就是单线程操作了。

上一篇 下一篇

猜你喜欢

热点阅读