我的代码中存在死锁/访问冲突,即使我已经相互排除了它

Deadlock / Access violation in my code even though I've mutually excluded it

本文关键字:排除 存在 代码 死锁 访问冲突 我的      更新时间:2023-10-16

所以我试图更好地理解多线程,死锁是如何发生的,以及如何避免它们,所以我把一小段代码放在一起。基本上我有两个线程共享一个 int 指针。

每个线程读取和写入指向的值。当线程写入(将值增加 1)时,我会在其周围锁定全局互斥锁。当它读取(将其连接到控制台)时,我将全局互斥锁锁定在它周围。

首先是我的代码:

    // DeadLockTest.cpp
    //
    #include "stdafx.h"
    #include <iostream>
    #include <thread>
    #include <mutex>
    using namespace std;
    void foo(int* p);
    void bar(int* p);
    mutex mut;
    int _tmain(int argc, _TCHAR* argv[])
    {
            int x = 5;
            int* p = &x;
            thread first(bind(foo, p));
            thread second(bind(bar, p));
            first.join();
            second.join();
            cout << "threads done";
            cin.ignore();
            return 0;
    }
    void foo(int* p){
            int i = 0;
            while(1){
                    i++;
                    mut.lock();
                    *p++;
                    mut.unlock();
                    mut.lock();
                    cout << "foo: " << *p << endl;
                    mut.unlock();
            }
    }
    void bar(int* p){
            int i = 0;
            while(1){
                    i++;
                    mut.lock();
                    *p--;
                    mut.unlock();
                    mut.lock();
                    cout << "bar" << *p << endl;
                    mut.unlock();
            }
    }

我最终得到了一个例外:

死锁测试.exe 0x008E608F时未处理的异常: 0xC0000005:访问冲突读取位置0x003B0000。

首先,为什么会出现异常?我已经相互锁定了资源,使其无法从其他线程访问。如果我做错了什么,这就引出了另一个问题。异常总是发生在 foo 中的 cout 语句上,它永远不会发生在其他任何地方(甚至在柱线线程中也没有)。为什么只有 foo 线程,为什么只在 cout 语句上?当我减少/增加参考值时怎么办?

其次,每个线程都应该使用自己的互斥锁吗?或者可以使用全局共享的互斥锁吗?线程使用自己的本地互斥锁与全局共享互斥锁之间有什么区别?

第三,如果我的线程上有一个条件,所以它们不会无限运行,为什么:

cout << "threads done";

在两个线程完成后被调用?这两个线程是异步运行的,不是吗?

只是想为将来更好地理解这一点。

我在 Linux 上尝试过,用 g++ -std=c++0x -pthread foo.cpp -o foo 编译,这里也出现了段错误。

但是,我只是尝试将*p++*p--更改为(*p)++(*p)--,它奏效了!

问题是您正在递增和递减指针,而不是指向的值。 试试这个:

#include <iostream>
using namespace std;
int main() {
  int i = 123;
  int *p;
  p = &i;
  cout << *p++ << endl;
  cout << *p++ << endl;
  cout << *p++ << endl;
  cout << *p++ << endl;
  cout << *p++ << endl;
}

输出为:

123
-166656888
32767
0
0

现在,您将了解访问冲突意味着您正在尝试访问无法访问的内存。这表示您有一个指针指向您不希望它指向的位置。

因此,当您执行*p++时,您是在增加指针,而不是值。通过首先取消引用,通过执行(*p),您可以确保更改的是而不是指针。