2012-02-25 8 views
-1

スピンロックとミューテックスロックを実装するコードを書いた。
興味深いがありますが。魔法の呪文は私のプログラムを生かし続けることができます。私が傷を取り除くと、私のプログラムは永遠に眠っています。 (これはLinuxでのみ起こります。Windowsはうまくいっています)
いずれかの手掛かりがありますか?私のプログラムを生かし続ける魔法の呪文

#include <pthread.h> 
#include <iostream> 
#include <queue> 
#include <sys/time.h> 
#include <stdexcept> 
#include <cstdio> 
#include <cstdlib> 
using namespace std; 

#define Tcount 10 
#define TheLock MutexLock 

static inline int TAS(volatile int * ptr) { 
    unsigned long result; 
    asm volatile("lock;" 
       "xchgl %0, %1;" 
       : "=r"(result), "=m"(*ptr) 
       : "0"(1), "m"(*ptr) 
       : "memory"); 
    return result; 
} 




class SpinLock { 
private: 
    int lock; 
    pthread_t owner; 
public: 

    SpinLock() { 
     lock = 0; 
    } 

    void getLock() { 
     while (TAS(&lock) == 1) { 

     } 

     owner = pthread_self(); 

    } 

    void releaseLock() { 
     if (lock == 0) { 
      cout << "Spin no lock" << endl; 
      return; 
     } else if (owner == pthread_self()) { 
      owner = NULL; 
      lock = 0; 
     } else { 
      throw runtime_error("Spin can't release"); 
     } 
    } 


}; 

class MutexLock { 
private: 
    int lock; 
    pthread_t owner; 
    queue<pthread_t> q; 
    SpinLock qLock; 
public: 

    MutexLock() { 
     lock = 0; 
    } 

    void getLock(int id) { 
     pthread_t self = pthread_self(); 
    cout<<"a"<<endl;// magic cout 

     if (TAS(&lock) == 0) { 
      owner = self; 
      return; 
     } 
     qLock.getLock(); 
     q.push(self); 
     qLock.releaseLock(); 

     while (owner != self) { 
     } 

    } 

    void releaseLock(int id) { 
     if (lock == 0) { 
      cout << "Mutex no lock" << endl; 
      return; 
     } else if (owner == pthread_self()) { 
      qLock.getLock(); 
      if (q.empty()) { 
       owner = NULL; 
       lock = 0; 
      } else { 
     owner = q.front(); 
       q.pop();   
      } 
      qLock.releaseLock(); 
     } else { 
       throw runtime_error("Mutex can't release"); 
     } 
    } 
}; 

TheLock lock; 
int g = 0; 
void* run(void* pt) { 

    int id = (int) pt; 
    for (int i = 0; i < 10000; i++) { 

     lock.getLock(id); 
     //cout<<"Thread "<<id<<" get lock, g="<<g<<endl; 
     int next = g + 1; 
     g = next; 
     //cout<<"Thread "<<id<<" release lock, g="<<g<<endl; 
     lock.releaseLock(id); 


    } 

    return NULL; 

} 

int main() { 

    pthread_t th[Tcount]; 

    long mtime, seconds, useconds; 
    struct timeval start, end; 
    gettimeofday(&start, NULL); 

    for (int i = 0; i < Tcount; i++) { 
     pthread_create(&th[i], NULL, run, (void*) (i+10)); 
    } 
    for (int i = 0; i < Tcount; i++) { 
     pthread_join(th[i], 0); 
    } 
    gettimeofday(&end, NULL); 

    seconds = end.tv_sec - start.tv_sec; 
    useconds = end.tv_usec - start.tv_usec; 

    mtime = ((seconds) * 1000000 + useconds); 

    cout << "g=" << g << endl; 
    cout << "time=" << mtime << endl; 



    return 0; 
} 
+0

最小限のコード例、約20行のコードに縮小してみてください。 –

+0

問題を示す最小の例を作成できますか? – bames53

答えて

2

操作はアトミックではないかもしれないとして、あなたはvolatileキーワードを使用してミューテックスを実装することはできません。これは、操作が完了する前にOSが別のスレッドに切り替える可能性があることを意味します。

ミューテックスの場合、OSを使用する必要があります。これは、スレッドが切り替えられていることを知っている唯一のものです。

+0

申し訳ありません私はあなたが意味するものを理解することができません..... – user956159

+2

BasciallyあなたはC++(またはthaatの問題のための他の言語)でmutexを実装することはできません。オペレーティングシステムによってあなたに与えられます。上のコードは役に立たない。 'volatile'キーワードは、プログラムによって定義されていない他の方法(時計など)を徹底的に変更する可能性があるため、コンパイラが最適化を実行しないことを意味します。 –

関連する問題