2012-08-02 128 views
1

我有这个简单的线程创建progrm在C++中,当全局声明RW锁时,progrmm按预期方式执行,但是当相同的锁定声明是本地(即函数内部)只有一个线程执行,另一个线程挂起。线程挂起在pthread_rwlock_t

工作:

#include <iostream> 
#include <pthread.h> 

using namespace std; 
int i = 0; 
**pthread_rwlock_t mylock;** //GLOBAL 

void* IncrementCounter(void *dummy) 
{ 
    cout << "Thread ID " << pthread_self() << endl; 
    int cnt = 1; 
    while (cnt < 50) 
    { 
     pthread_rwlock_wrlock(&mylock); 
     ++i; 
     pthread_rwlock_unlock(&mylock); 
     ++cnt; 
    cout << "Thread ID (" << pthread_self() << ") Incremented Value : " << i << endl; 
    } 

} 
int main() 
{ 
     pthread_t thread1,thread2; 
     int ret, ret1; 
     ret = pthread_create(&thread1,NULL,IncrementCounter,NULL); 
     ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL); 
     pthread_join(thread1,NULL); 
     pthread_join(thread2,NULL); 

} 

* 非工作: *

#include <iostream> 
#include <pthread.h> 

using namespace std; 
int i = 0; 

void* IncrementCounter(void *dummy) 
{ 
    cout << "Thread ID " << pthread_self() << endl; 
    int cnt = 1; 
    **pthread_rwlock_t mylock;** //LOCAL 
    while (cnt < 50) 
    { 
     pthread_rwlock_wrlock(&mylock); 
     ++i; 
     pthread_rwlock_unlock(&mylock); 
     ++cnt; 
    cout << "Thread ID (" << pthread_self() << ") Incremented Value : " << i << endl; 
    } 

} 
int main() 
{ 
     pthread_t thread1,thread2; 
     int ret, ret1; 
     ret = pthread_create(&thread1,NULL,IncrementCounter,NULL); 
     ret1 = pthread_create(&thread2,NULL,IncrementCounter,NULL); 
     pthread_join(thread1,NULL); 
     pthread_join(thread2,NULL); 

} 

可能是什么可能的原因?

回答

4

在任何情况下,您都无法正确初始化mylock变量 - 在第一种情况下,您刚刚获得“幸运”。在全球情况下正确的初始化是:

pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER; 

在当地的情况下,如果你希望你的线程能够访问相同锁,那么它已经被宣布static

static pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER; 

这就是你想要的,因为你正在保护对全球i的访问。锁应该与数据相关联,所以如果i是全球性的,那么确实mylock也是全球性的。


如果你真的非静态锁(在这种情况下,你不这样做),你可以使用:

pthread_rwlock_t mylock; 

pthread_rwlock_init(&mylock, NULL); 

依次为:

pthread_rwlock_destroy(&mylock); 

在函数结束时。

+0

谢谢大家澄清。我知道为全局变量设置两个锁没有意义。但是如果有两个锁,那么它们将会是不同的锁,所以如果一个锁解锁,另一个将锁定,为什么它会死锁? 不应该用2个不同的锁来锁定一个全局变量吗?你能否详细说明一下? – user1570478 2012-08-02 08:11:05

+0

@ user1570478:这是死锁,因为您没有正确初始化锁,不是因为有两个锁。当你使用未初始化的锁时,任何事情都可能发生。 – caf 2012-08-02 08:27:11

0

原因很清楚,你甚至可以自己这么说......在工作版本中,变量是全局变量,而在非工作变量中,变量是局部变量。

在调用期间,局部变量只在函数内部是已知的。所以如果一个函数被调用两次,那么这两个调用的变量都是唯一的。

如果你想使用一个局部变量,你可以将它标记为static,因为它使得它在函数的所有调用之间都是“静态的”。

我建议你阅读更多关于变量范围和生命周期。

+0

谢谢你们的澄清。我知道为全局变量设置两个锁没有意义。但是如果有两个锁,那么它们将会是不同的锁,所以如果一个锁解锁,另一个将锁定,为什么它会死锁?不应该用2个不同的锁来锁定一个全局变量吗?你能否详细说明一下? – user1570478 2012-08-02 08:11:34

+0

@ user1570478由于锁未正确初始化,它可能会死锁?查看来自caf的回答。 – 2012-08-02 08:24:47

1

除了其他答案的内容之外,还应该考虑在C和C++中,所有带有静态存储的变量(例如第一个示例中的mylock)都被初始化为零。 简化,pthread_rwlock_tstruct

在第一个示例中,mylock具有静态存储持续时间,因此其所有内部成员都初始化为零。偶然地,这相当于pthread_rwlock_t的“解锁”状态,因为在另一个答案中提到的宏PTHREAD_RWLOCK_INITIALIZER正好将所有东西初始化为零;在nptl/sysdeps/pthread/pthread.h你可以找到:

#define PTHREAD_RWLOCK_INITIALIZER \ 
{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } 

因此,所有你的第一个例子的运行总是会出现相同的行为(即锁将开始解锁)。

在第二个示例中,mylock未初始化,因为它具有自动存储持续时间。这种行为将取决于其他值发生在未初始化的内存区域上。大多数情况下,开始处于“锁定”状态的锁定,但如果运气够好(不幸),就会开始解锁。

+0

请注意,这仅适用于pthread的一个特定实现 - 在其他实现中,“PTHREAD_RWLOCK_INITIALIZER”可能非零(否则根本不需要存在!)。 – caf 2012-08-02 08:33:23

+0

正确;我想'PTHREAD_RWLOCK_INITIALIZER'是为了交叉实现和/或跨版本的兼容性,而不是良好的编码实践。 – 2012-08-02 17:44:56

+0

是的,例如pthreads-w32使用'((pthread_rwlock_t)-1)'。 – caf 2012-08-03 05:34:08