1

私は C++ でこの単純なスレッド作成プログラムを持っています。RW ロックがグローバルに宣言されている間、progrmm は期待どおりに実行されますが、同じロック宣言がローカル (つまり、関数内) にされると、1 つのスレッドのみが実行され、他のスレッドがハングします。

働く:

#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

3 に答える 3

5

どちらの場合も、mylock変数を正しく初期化していません。最初のケースでは「幸運」になっているだけです。グローバルな場合の正しい初期化は次のようになります。

pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER;

ローカルの場合、スレッドが同じロックにアクセスできるようにするには、次のように宣言する必要がありますstatic

static pthread_rwlock_t mylock = PTHREAD_RWLOCK_INITIALIZER;

global へのアクセスを保護しているため、この場合はそれが必要ですi。ロックはデータに関連付ける必要があるため、がグローバルである場合iは、グローバルであることも理にかなっていmylockます。


非静的ロックが本当に必要な場合(この場合は必要ありません)、次を使用します。

pthread_rwlock_t mylock;

pthread_rwlock_init(&mylock, NULL);

に続く:

pthread_rwlock_destroy(&mylock);

関数の最後に。

于 2012-08-02T06:36:31.487 に答える
2

他の回答が言うことに加えて、C および C++ では、静的ストレージを持つすべての変数 (たとえばmylock、最初の例) がゼロに初期化されることを考慮してください。単純化するpthread_rwlock_tと、 ですstruct

最初の例で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 } }  

したがって、最初の例のすべての実行は、常に同じ動作を示します (つまり、ロックはロック解除された状態で開始されます)。

2番目の例でmylockは、自動保存期間があるため、初期化されていません。動作は、初期化されていないメモリ領域にある他の値に依存します。ほとんどの場合、ロックは「ロックされた」状態で始まりますが、運が良ければ (不運な場合)、代わりにロックが解除されます。

于 2012-08-02T06:59:57.950 に答える
1

その理由は非常に明確です。ご自身でもそうおっしゃっています...動作中のバージョンでは変数はグローバルですが、動作していないバージョンでは変数はローカルです。

ローカル変数は、その呼び出し中、関数内でのみ認識されます。したがって、関数が 2 回呼び出された場合、変数はこれらの呼び出しの両方で一意になります。

staticローカル変数を使用する場合は、関数のすべての呼び出し間で「静的」にするため、それをマークできます。

変数のスコープと有効期間についてもっと読むことをお勧めします。

于 2012-08-02T06:37:07.680 に答える