动态顺序栈和线程安全的堆栈类

1、动态顺序栈

固定大小的栈的容量可能随着参数数目的增加或者递归层数的增加而溢出,故此可用动态栈代替,实现思路较为简单,每次元素入栈前判断一下栈容量是否足够,不够的话增加容量,通过栈底指针移动。以下是参考代码:

#ifndef DY_STACK_H_INCLUDED
#define DY_STACK_H_INCLUDED
#include <malloc.h>
#include <stdlib.h>
#define STACK_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define ERROR -1
typedef int Status;
typedef int ElemType;
typedef struct Dysqstack
{
    ElemType *top;
    ElemType *bottom;
    int stacksize;
}DySqStack;
//init
Status DySqStack_Init(DySqStack &S)
{
    S.bottom=(ElemType *)malloc(STACK_SIZE*sizeof(ElemType));
    if(!S.bottom) return ERROR;
    S.top=S.bottom;
    S.stacksize=STACK_SIZE;
    return OK;
}
//push data to stack
Status DySqStack_Push(DySqStack &S,ElemType e)
{
    //if size of stack is not enough,add the size by function named realloc
    if(S.top-S.bottom>=S.stacksize-1)
    {
        S.bottom=(ElemType *)realloc(S.bottom,(STACKINCREMENT+STACK_SIZE)*sizeof(ElemType));
        if(!S.bottom) return ERROR;
        S.top=S.bottom+S.stacksize;
        S.stacksize=S.stacksize+STACKINCREMENT;
    }
    S.top++;
    *(S.top)=e;
    return OK;
}
//pop data from stack
Status DySqStack_Pop(DySqStack &S,ElemType *e)
{
    if(S.bottom==S.top)
    {
        std::cout<<"stack is empty!"<<std::endl;
        return ERROR;
    }
    *e=*(S.top);
    S.top--;
    return OK;
}
Status DySqStack_notEmpty(DySqStack &S)
{
    if(S.bottom==S.top)
    {
        std::cout<<"stack is empty!"<<std::endl;
        return ERROR;
    }
    return OK;
}
Status DySqStack_Top(DySqStack &S,ElemType *e)
{
    if(S.bottom==S.top)
    {
        std::cout<<"stack is empty!"<<std::endl;
        return ERROR;
    }
    *e=*(S.top);
    return OK;
}
#endif // DY_STACK_H_INCLUDED

2、线程安全的堆栈类

标准库中的stack结构是非线程安全的,为什么这么说呢?考虑一下stack的pop方法和top方法,pop方法只是出栈操作,top方法是取栈顶元素,设想一下有两个线程A和B,对某一个公共stack进行操作, 某一时刻A获得了stack的锁,A需要获取它的栈顶元素,而B则弹出它,需要top和pop两个方法,这就有个问题,我们这样写代码: if(!s,empty()) x=s.top();s.pop();当A调用了empty和top后,B可能调用pop弹出了最后一个元素使其成为空栈,而对空栈top是未定义的行为。这就是接口固有的条件竞争问题。

这里有个方法可以避免:

一、传入一个引用;

二、返回指向弹出值的指针;

#ifndef THREADSAFESTACK_H_INCLUDED
#define THREADSAFESTACK_H_INCLUDED
#include <memory>
#include <exception>
#include <mutex>
#include <stack>
struct empty_stack : std::exception
{
    const char* what() const throw() {
        return "empty stack!";
    };
};

template<typename T>
class threadsafe_stack
{
private:
    std::stack<T> data;
    mutable std::mutex m;
public:
    threadsafe_stack() : data(std::stack<int>()) {};
    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)
    {
        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()
    {
        std::lock_guard<std::mutex> lock(m);
        return data.empty();
    }
};
#endif // THREADSAFESTACK_H_INCLUDED

下边是测试代码:

#include <iostream>
#include <thread>
#include <cmath>
#include <cstdlib>
#include <windows.h>
#include "threadsafestack.h"
using namespace std;
threadsafe_stack<int> s;
void fun1()
{
    int value;
    for(int i=1;i<=10;i++)
    {
        s.push(i);
    }
    while(!s.empty())
    {
        s.pop(value);
        cout<<value<<endl;
    }
}
void fun2()
{
    int value;
    for(int i=11;i<=20;i++)
    {
        s.push(i);
    }
    while(!s.empty())
    {
        s.pop(value);
        cout<<value<<endl;
    }
}
void read()
{
    int value;
    while(1)
    {
        Sleep(1000);
    if(!s.empty())
    {
        s.pop(value);
        cout<<"read: "<<endl;
        cout<<value<<endl;
    }
    }
}
void write()
{
    while(1){
       Sleep(1000);
    srand((unsigned)time(NULL));
    int t=rand()%100;
    s.push(t);
    cout<<"write: "<<endl;
    cout<<t<<endl;
    }
}
int main()
{
    thread t1(read);
    thread t2(write);
    t1.join();
    t2.join();
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值