Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C+中实现线程安全的通用堆栈+;在linux上 在最近的一次访谈中,我被要求在Linux机器上实现C++中的一个线程安全的泛型(即基于模板的)堆栈。 我很快想到了以下内容(可能有编译错误)。 我接通了。面试官可能喜欢这个实现中的一些东西。可能是设计部分:) 此实现可能存在以下几个问题:- 1.指示溢出/下溢的执行不正确。没有溢出处理,因为我使用STL向量作为底层数据结构。应该有这样的处理吗?此外,下溢(在Pop()中)产生false作为返回值。应该通过抛出异常来完成吗? 2.PopElem例程的实现。以下实现是否正确? 3.没有真正使用top元素。 4.编写器线程和读取器线程之间的时间安排更好_C++_Multithreading_Stl - Fatal编程技术网

在C+中实现线程安全的通用堆栈+;在linux上 在最近的一次访谈中,我被要求在Linux机器上实现C++中的一个线程安全的泛型(即基于模板的)堆栈。 我很快想到了以下内容(可能有编译错误)。 我接通了。面试官可能喜欢这个实现中的一些东西。可能是设计部分:) 此实现可能存在以下几个问题:- 1.指示溢出/下溢的执行不正确。没有溢出处理,因为我使用STL向量作为底层数据结构。应该有这样的处理吗?此外,下溢(在Pop()中)产生false作为返回值。应该通过抛出异常来完成吗? 2.PopElem例程的实现。以下实现是否正确? 3.没有真正使用top元素。 4.编写器线程和读取器线程之间的时间安排更好

在C+中实现线程安全的通用堆栈+;在linux上 在最近的一次访谈中,我被要求在Linux机器上实现C++中的一个线程安全的泛型(即基于模板的)堆栈。 我很快想到了以下内容(可能有编译错误)。 我接通了。面试官可能喜欢这个实现中的一些东西。可能是设计部分:) 此实现可能存在以下几个问题:- 1.指示溢出/下溢的执行不正确。没有溢出处理,因为我使用STL向量作为底层数据结构。应该有这样的处理吗?此外,下溢(在Pop()中)产生false作为返回值。应该通过抛出异常来完成吗? 2.PopElem例程的实现。以下实现是否正确? 3.没有真正使用top元素。 4.编写器线程和读取器线程之间的时间安排更好,c++,multithreading,stl,C++,Multithreading,Stl,请提出任何意见/建议/改进。 谢谢 //实现线程安全的泛型堆栈 #include<pthread.h> #include<iostream> #include<vector> using namespace std; template<typename T> class MyStack { public: //interface bool Push(T elem); bool Pop(T& elem); bool IsEmpty();

请提出任何意见/建议/改进。
谢谢

//实现线程安全的泛型堆栈

#include<pthread.h>
#include<iostream>
#include<vector>

using namespace std;

template<typename T>
class MyStack
{
public:
//interface
bool Push(T elem);
bool Pop(T& elem);
bool IsEmpty();

//constructor
MyStack() {
pthread_mutex_init(&lock);
top = 0;
}

//destructor
~MyStack() {
pthread_mutex_destroy(&lock);
}

private:
pthread_mutex_t lock;
int top;
vector<T> stack;

bool MyStack::Push(T elem);
bool MyStack::PopElem(T& elem);
}; //end of MyStack

template<typename T>
bool MyStack<T>::Push(T elem)
{
    pthread_mutex_lock(&lock);
    PushElem(elem);
    pthread_mutex_unlock(&lock);
}

template<typename T>
bool MyStack<T>::Pop(T& elem)
{
    pthread_mutex_lock(&lock);
    PopElem(elem);
    pthread_mutex_unlock(&lock);
}

template<typename T>
bool MyStack<T>::PushElem(T elem)
{
    stack.push_back(elem);
     top = stack.size();
}

template<typename T>
bool MyStack<T>::PopElem(T& elem)
{
   if(this.IsEmpty())
   {
        return false;
   }

   elem = stack.back(); //tricky, returns a reference to the last element
   stack.pop_back(); // is elem valid after this ??
   top = stack.size();
   return true;
}      


template<typename T>
bool MyStack<T>::IsEmpty()
{
    return stack.empty();
}


class MyStackTest
{
public:
  void Initialize() {
  pthread_init(&readerT);
  pthread_init(&writerT);
  }

  void Run() {
 pthread_create(writerT,0,writer,0); 
 pthread_create(readerT,0,reader,0);
 pthread_join(&writerT);
 pthread_join(&readerT);
}

private:
pthread_t readerT;
pthread_t writerT;
MyStack<int> stack;

void reader(void);
void writer(void);
};

void MyStackTest::writer() {
  for(int i=0;i<20;i++) {
      stack.Push(i);
      cout<<"\n\t Pushed element: "<<i;
   } //end for
}

void MyStackTest::reader() {
   int elem;
   while(stack.Pop(elem))
   {
     cout<<"\n\t Popped: "<<elem;
   }
}

int main()
{
    MyStackTest Test;

    Test.Run();
}
#包括
#包括
#包括
使用名称空间std;
模板
类MyStack
{
公众:
//接口
bool-Push(T-elem);
布尔波普(T&elem);
bool是空的();
//建造师
MyStack(){
pthread_mutex_init(&lock);
top=0;
}
//析构函数
~MyStack(){
pthread_mutex_destroy(&lock);
}
私人:
pthread_mutex_t lock;
int top;
矢量叠加;
bool-MyStack::Push(T元素);
波尔·迈斯塔克:波佩莱姆(T&elem);
}; //MyStack的结尾
模板
bool MyStack::Push(T元素)
{
pthread_mutex_lock(&lock);
普希伦;
pthread_mutex_unlock(&lock);
}
模板
bool MyStack::Pop(T&elem)
{
pthread_mutex_lock(&lock);
波普莱姆;
pthread_mutex_unlock(&lock);
}
模板
bool MyStack::PushElem(T elem)
{
堆叠。推回(elem);
top=stack.size();
}
模板
波尔·迈斯塔克::波普莱姆(T&elem)
{
if(this.IsEmpty())
{
返回false;
}
elem=stack.back();//返回对最后一个元素的引用
stack.pop_back();//在此之后元素有效吗??
top=stack.size();
返回true;
}      
模板
bool MyStack::IsEmpty()
{
返回stack.empty();
}
课堂测试
{
公众:
void Initialize(){
pthread_init(&readerT);
pthread_init(&writerT);
}
无效运行(){
pthread_create(writerT,0,writer,0);
pthread_create(readerT,0,reader,0);
pthread_连接(&writerT);
pthread_join(&readerT);
}
私人:
pthread_t readerT;
pthread_t writerT;
MyStack堆栈;
作废阅读器(作废);
无效作者(void);
};
void MyStackTest::writer(){
对于(int i=0;i某些问题:

  • 我将实现一个Locker类来使用RAII声明和释放互斥锁
  • 我会使用std::stack

  • 我会让std::stack的用户使用Locker来实现锁定策略——拥有一个锁定自身的堆栈是糟糕的设计,因为堆栈不知道如何使用它

我会添加一个条件变量,以便“poppers”可以在不消耗CPU时间的情况下等待

//棘手的是,返回对最后一个元素的引用

赋值会在最后一个元素弹出向量之前复制它,这样就可以了

正如你所说,“top”是没有意义的。你可以随时获取向量的大小

您应该只调用stack.empty()由于锁不存在,因为它不能保证它是一个原子访问。如果你调用它,而另一个线程在更新堆栈的中间,你会得到一个不一致的答案。所以你的公共IsEmpty函数应该使用互斥体,这意味着你不想从别处调用它。 但无论如何,IsEmpty在并行代码中并不是很有用。仅仅因为调用它时它为false并不意味着当你弹出一行时它仍然为false。因此,要么你应该从公共接口中删除它,要么你应该公开锁以便用户可以编写自己的原子操作。在这种情况下,我不会有任何下溢除了在调试模式下的断言之外,我根本不相信会有人在不阅读文档或测试代码的情况下,对那些达到发布模式的人百依百顺

[编辑:如何将RAII用于锁

当人们说使用RAII进行锁定时,他们的意思不仅仅是确保互斥锁被破坏。他们的意思是使用它来确保互斥锁被解锁。关键是如果你有如下代码:

lock();
doSomething();
unlock();
doSomething()抛出一个异常,那么您将无法解锁互斥锁。哎哟

下面是一个示例类以及用法:

class LockSession;
class Lock {
    friend class LockSession;
    public:
    Lock()        { pthread_mutex_init(&lock); }
    ~Lock()       { pthread_mutex_destroy(&lock); }

    private:
    void lock()   { pthread_mutex_lock(&lock); }
    void unlock() { pthread_mutex_unlock(&lock); }

    private:
    Lock(const Lock &);
    const Lock &operator=(const Lock &);

    private:
    pthread_mutex_t lock;
};

class LockSession {
    LockSession(Lock &l): lock(l) { lock.lock(); }
    ~LockSession()                { lock.unlock(); }
    private:
    LockSession(const LockSession &);
    LockSession &operator=(const LockSession &);

    private:
    Lock &lock;
};
然后,在某个地方,您的代码将有一个与要保护的数据关联的锁,并将使用它,如下所示:

void doSomethingWithLock() {
    LockSession session(lock);
    doSomething();
}

现在不管是
doSomething()
抛出异常还是正常返回(在第二个示例中,
doSomethingElse
不会发生异常,但我假设在错误情况下不需要这样做)。无论哪种方式,
会话
都会被销毁,其析构函数会释放互斥。特别是,堆栈上的“推送”等操作会分配内存,因此可能会抛出,因此您需要处理这一问题

RAII代表资源获取是初始化。在doSomethingWithLock()的情况下,您想要获取的资源是您想要持有锁。因此,您编写了一个类,它允许您通过初始化一个对象(LockSession)来实现这一点。当对象被销毁时,锁被放弃。因此您正在处理“锁定/解锁互斥体”的处理方式与“初始化/解除初始化互斥体”的处理方式完全相同,并且您以相同的方式保护自己免受资源泄漏

一个稍微让人恼火的事实是,这段代码完全被破坏了,而且有bug,您必须确保不要意外地这样做,即使在粗心的人看来,它就像正确的代码一样:

void doSomethingWithLock() {
    LockSession(lock);
    doSomething();
}
在这里,第一行创建一个临时对象并立即销毁它,再次释放锁。
doSomething()
不是调用
void doSomethingWithLock() {
    LockSession(lock);
    doSomething();
}
template<typename T> 
class MyStack
{
public:
//interface
bool Push(T elem);
bool Pop(T& elem);
bool IsEmpty();

//constructor
MyStack() {
//top = 0;
}

//destructor
~MyStack() {

}

private:
    class Locker {          //RAII
    public:
        Locker() {
            pthread_mutex_init(&lock);
        }
        ~Locker() {
            pthread_mutex_destroy(&lock);
        }
        void Lock() {
            pthread_mutex_lock(&lock);
        }
        void UnLock() {
            pthread_mutex_unlock(&lock);
        }
    private:
        pthread_mutex_t lock;
    };
Locker MyLock;
//int top;
stack<T> mystack;

bool MyStack::Push(T elem);
bool MyStack::PushElem(T elem);
bool MyStack::Pop(T& elem);
bool MyStack::PopElem(T& elem);
}; //end of MyStack

template<typename T>
bool MyStack<T>::Push(T elem)
{
    MyLock.Lock();
    PushElem(elem);
    MyLock.UnLock();
}

template<typename T>
bool MyStack<T>::Pop(T& elem)
{
    MyLock.Lock();
    PopElem(elem);
    MyLock.UnLock();
}