【问题标题】:Deadlock in C++ codeC++ 代码中的死锁
【发布时间】:2015-10-30 17:50:46
【问题描述】:

我尝试处理我的代码中的死锁,但我不知道如何防止它。我有一个访问数据的线程和一个更新数据的更新方法。代码如下所示:

thread {
    forever {
        if (Running) {
            LOCK
                access data
            UNLOCK
        }
         Running = false;
    }
}

update {
    Running = false;

    LOCK
        access data
    UNLOCK

    Running = true;
}

我尝试使用第二个访问变量来修复它,但它并没有改变任何东西。

thread {
    forever {
        if (!Updating) {
            if (Running) {
                LOCK
                     access data
                UNLOCK
            }
        }
         Running = false;
    }
}

update {
    Updating = true;
    Running = false;

    LOCK
        access data
    UNLOCK

    Updating = false;
    Running = true;
}

感谢您的帮助。

更新 这是对问题的更好描述:

thread {
    forever {
        if (Running) {
            LOCK
                if (!Running) leave
                access data
            UNLOCK
        }
        Running = false;
    }
}

update {
    Running = false;

    LOCK
        access data
    UNLOCK

    Running = true;
}

我的更新函数有点复杂,所以我看不到为此使用标准算法之一的方法。

更新 2 这是简化的 c++ 源代码。也许将其作为伪代码阅读会更好:

void run() {
    forever {
        if (mRunning) {

            QMutexLocker locker(&mMutex);
            for (int i; i < 10; i++) {
                qDebug("run %d", i);
                sleep(1);
                if (!mRunning) break;
            }

            mRunning = false;
        }
    }
}

void update() {
    mRunning = false;

    QMutexLocker locker(&mMutex);

    qDebug("update");

    mRunning = true;
}

更新 3 行。问题有点复杂。我忘了我在线程中的访问数据部分也开始了一些子线程来填充数据结构

datathread {
    access data
}

thread {
    forever {
        if (Running) {
            LOCK
                if (!Running) leave

                forloop
                    start datathread to fill data to accessdata list
            UNLOCK
        }
        Running = false;
    }
}

update {
    Running = false;

    LOCK
        access data
    UNLOCK

    Running = true;
}

【问题讨论】:

  • 谢谢。我已经阅读了这篇文章,也搜索了它。
  • 如果我在我的第一个示例中添加一个 sleep(1) 在我的永远循环后面,那么一切都会正常工作。
  • @adapto Updating = true;Updating = false; 也应该是原子操作。 Running 状态可能也需要相同的条件。
  • 在使用单个互斥锁的代码中不可能出现死锁(除非您尝试在已经拥有它的代码中加锁)。你到底是什么问题?

标签: c++ qt concurrency deadlock


【解决方案1】:

write 期间重新启动read 方法的标准方法是使用seqlock。对于单个 writerreader,seqlock 只是原子整数变量,每次 writer 启动和结束时都会递增。这样 reader 方法可以周期性地检查变量是否在 read 启动后没有改变:

atomic<int> seq = 0;

updater() // *writer*
{
    seq = seq + 1;
    <update data>
    seq = seq + 1;
}

thread() // *reader*
{
     retry: // Start point of unmodified data processing.
     {
         int seq_old = seq;
         if(seq_old & 1)
         {
              // odd value of the counter means that updater is in progress
              goto retry;
         }

         for(int i = 0; i < 10; i++)
         {
             <process data[i]>
             if(seq_old != seq)
             {
                 // updater has been started. Restart processing.
                 goto retry;
             }
         }
         // Data processing is done.
     }
}

如果多个 updater() 可以同时执行,整个update 代码应该使用互斥锁执行:

updater() // *writer*
{
    QMutexLocker locker(&updater_Mutex);

    seq = seq + 1;
    <update data>
    seq = seq + 1;
}

如果更新时甚至不能同时访问单个数据元素,则&lt;update data&gt;&lt;process data[i]&gt; 都应该在执行时使用互斥锁。

【讨论】:

  • 感谢您的解释。但这无助于解决我的问题。我想我需要添加一些线程计数器。就像我在第三次更新中解释的那样,循环启动了单独的线程,你不知道它们中的哪些现在完成了,还有多少线程正在进行中。这就是我无法完成循环的原因。我以前没有看到这一点,但现在我确信这种结构使得使用这种标准方法变得不可能。如果你使用这样的开关,你只能控制一个线程。
  • 我想我必须对启动的线程进行计数,然后我需要等待所有启动的线程都完成后才能离开循环。
  • 在任何情况下,您都应该等待所有启动的线程,即使在它们执行期间没有发生update() 调用。另一方面,这些线程也可以检查seq 计数器,如果计数器已更改,则终止下载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多