我的代码中存在死锁/访问冲突,即使我已经相互排除了它
Deadlock / Access violation in my code even though I've mutually excluded it
所以我试图更好地理解多线程,死锁是如何发生的,以及如何避免它们,所以我把一小段代码放在一起。基本上我有两个线程共享一个 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)
,您可以确保更改的是值而不是指针。
- C++模板来检查友元函数的存在
- 既然存在危险,为什么项目要使用-I include开关
- 我们可以访问一个不存在的联盟的成员吗
- C++:对不存在的命名空间使用命名空间指令
- C++quit()函数中可能存在作用域问题
- C++擦除(如果存在)
- g++ 说函数不存在,即使包含正确的标头
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 有了gcc,是否可以链接库,但前提是它存在
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- C++Builder中的OnClick事件签名存在问题
- 如何正确地将分支添加到已存在的树中
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 如何检查QList中是否存在值
- 根据某个函数是否存在启用模板
- 如何将分支添加到已存在的TTree:ROOT
- 地图计数确实很重要,或者只是检查是否存在
- 通用C++/Python 多语言的存在
- 为什么我的共享库中存在展开符号