所以我试图更好地理解多线程以及死锁是如何发生的以及如何避免它们因此我将一小段代码放在一起。基本上我有两个共享一个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();
}
}
我最终得到一个例外:
DeadLockTest.exe中0x008E608F处的未处理异常:0xC0000005:访问冲突读取位置0x003B0000。
首先,为什么我会得到例外?我已经从另一个线程中相互锁定了资源。如果我做错了什么,这会导致另一个问题。异常总是发生在foo的cout语句中,它永远不会发生在其他任何地方(甚至不在bar线程中)。为什么只有foo线程和为什么只在cout语句?当我减少/增加参考值时呢?
第二,每个线程应该使用自己的互斥锁吗?或者可以使用全局共享的互斥锁吗?线程使用自己的本地互斥体与其范围而不是全局共享的互斥体之间有什么区别?
第三,如果我的线程有条件,所以他们不能无限运行,为什么会这样:
cout << "threads done";
两个线程完成后会调用吗?这两个线程是异步运行的,没有?
试图在未来更好地理解这一点。
答案 0 :(得分:3)
我在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)
,确保它是值而不是更改的指针。