C++ C++;关键部分中的异常处理(pthreads)

C++ C++;关键部分中的异常处理(pthreads),c++,exception,mutex,pthreads,C++,Exception,Mutex,Pthreads,[编辑:(从评论中复制)事实证明,问题出在别处,但感谢大家的意见。] 我有一个共享容器类,它使用一个互斥锁来锁定push()和pop()函数,因为我不想同时修改head和tail。代码如下: int Queue::push( WorkUnit unit ) { pthread_mutex_lock( &_writeMutex ); int errorCode = 0; try { _queue.push_back( unit );

[编辑:(从评论中复制)事实证明,问题出在别处,但感谢大家的意见。]

我有一个共享容器类,它使用一个互斥锁来锁定push()和pop()函数,因为我不想同时修改head和tail。代码如下:

int Queue::push( WorkUnit unit )
{
    pthread_mutex_lock( &_writeMutex );
    int errorCode = 0;

    try
    {
        _queue.push_back( unit );
    }
    catch( std::bad_alloc )
    {
        errorCode = 1;
    }

    pthread_mutex_unlock( &_writeMutex );

    return errorCode;
}
当我在调试模式下运行时,一切都很顺利。当我在发布模式下运行时,我大概在驱动程序开始“同时”推送和弹出时崩溃。如果try/catch块捕获到std::bad_alloc异常,它是否会立即强制退出?如果是这样,我应该将函数的其余部分包含在finally块中吗

<>也可以,较慢的调试模式是否成功,因为我的推()和POP()调用实际上从来没有同时发生过?

< P>在C++中,我们用来防范异常。 try/catch是否立即阻塞 如果它抓住了一根绳子,就强行退出 std::错误的分配异常

否。如果在
try{…}
块中抛出std::bad_alloc,则
catch{…}
块中的代码将触发

如果您的程序实际上正在崩溃,那么您的push_-back调用似乎抛出了一些异常,而不是
bad_-alloc
(代码中没有处理该异常),或者
bad_-alloc
被抛出
try{…}
块之外的某个地方

顺便问一下,您确定要在这里使用try…catch块吗?

plus

流行音乐是什么样子的

创建一个锁包装器类,当锁超出范围时,该类将自动释放锁(如RAII comment中所示)

c++最终没有(多亏stoustrop先生的严厉批评)


我会抓住std::exception(异常)或者根本没有(鸭子们会低头去参加火焰战)。如果你没有抓到任何东西,那么你需要一个包装器,这真的是一个异常之后的爆炸吗?从您的代码片段来看,更可能的情况是您的同步不好。它以互斥体的名称开头:“writeMutex”。如果还有一个“readMutex”,这将不起作用。所有读取、窥视和写入操作都需要由相同的互斥锁锁定。

关于发布/调试:是的,您经常会发现两种类型的构建之间的竞争条件发生变化。处理同步时,线程将以不同级别的训练运行。写得好的线程通常会并发运行,而写得不好的线程则会以高度同步的方式相互关联。所有类型的同步都会产生某种级别的同步行为。这就好像同步和同步来自同一个根单词

因此,是的,考虑到调试和发布之间的运行时性能略有不同,线程同步的那些点有时会导致错误代码在一种类型的构建中出现,而不是在另一种类型的构建中出现。

您需要使用RAII
这基本上意味着使用构造函数/析构函数来锁定/解锁资源。
这保证了即使存在异常,互斥锁也将始终处于解锁状态

您只能使用一个互斥来访问列表。
即使只有只读的线程使用只读互斥锁。这并不意味着在另一个线程更新队列时读取是安全的。队列可能处于某个中间状态,这是由于另一个线程在尝试导航invlide中间状态时调用push()的线程造成的

class Locker
{
    public:
        Locker(pthread_mutex_t &lock)
            :m_mutex(lock)
        {
            pthread_mutex_lock(&m_mutex);
        }
        ~Locker()
        {
            pthread_mutex_unlock(&m_mutex);
        }
    private:
        pthread_mutex_t&    m_mutex;
};

int Queue::push( WorkUnit unit )
{
    // building the object lock calls the constructor thus locking the mutex.
    Locker  lock(_writeMutex);
    int errorCode = 0;

    try
    {
        _queue.push_back( unit );
    }
    catch( std::bad_alloc )  // Other exceptions may happen here.
    {                        // You catch one that you handle locally via error codes. 
        errorCode = 1;       // That is fine. But there are other exceptions to think about.
    }

    return errorCode;
}  // lock destructor called here. Thus unlocking the mutex.
另外,我讨厌使用前导下划线。

虽然从技术上讲,这是可以的(假设成员变量),但很容易搞砸,所以我不希望将“”预先挂起给IDNetifier。有关标识符名称中的“”要执行的规则的完整列表,请参阅。

先前的Locker类代码示例存在一个主要问题: 如果pthread_mutex_lock()失败,您会怎么做? 答案是,此时必须从构造函数中抛出一个异常,然后可以捕获它。 好的 然而, 根据C++异常规范,从析构函数中抛出异常是不存在的。
如何处理pthread\u mutex\u unlock故障?

在任何检测软件下运行代码都没有任何意义。 你需要正确的代码,而不是在valgrind下运行

在C语言中,它工作得非常好:

pthread_cleanup_pop( 0 );
r = pthread_mutex_unlock( &mutex );
if ( r != 0 )
{
    /* Explicit error handling at point of occurance goes here. */
}
<>但是因为C++是软件流产,所以没有合理的方法来处理任何有确定程度的线程编码失败。像将pthread_mutex_t包装到添加某种状态变量的类中这样的死脑筋的想法就是死脑筋。以下代码不起作用:

Locker::~Locker()
{
    if ( pthread_mutex_unlock( &mutex ) != 0 )
    {
        failed = true; // Nonsense.
    }
}
原因是,在pthread_mutex_unlock()返回后,这个线程很可能会从cpu中被切掉-抢占。这意味着.failed公共变量仍然是false。其他线程查看它会得到错误的信息-状态变量表示没有失败,同时pthread_mutex_unlock()失败。即使幸运的是,这两条语句一次性运行,这个线程也可能在~Locker()返回之前被抢占,其他线程可能会修改.failed的值。总之,这些方案不起作用——对于应用程序定义的变量,没有原子测试和设置机制


有人说,析构函数不应该有失败的代码。其他任何东西都是糟糕的设计。好的。我只是好奇地想知道什么是一个好的设计,在C++中是100%异常和线程安全的。不幸的是,我需要使用一个TI/catch块(它最终会捕获STD:无论如何,异常),因为在PUTH()函数中发生任何类型的故障时,调用函数可以选择自己的工作(而不是排队)。这是巨大CF的一部分,我们需要在没有编写大部分CF的开发人员的帮助下开始工作:(如我所说,我使用“一个互斥锁来锁定push()和pop()函数”,它恰好被称为“_writeMutex”。事实证明,问题出在别处,但谢谢