2016-10-18 7 views
0

C++で多対多のスレッドマネージャを実装することが任されています。私はそれを多かれ少なかれ持っているが、私はの方法でswapcontextと深刻な問題を抱えている。ここでは、コード多対多スレッドの実装でswapcontextが失敗する

/* 
* uthread.cpp 
* 
* Created on: Oct 12, 2016 
*  Author: michael 
*/ 

#include "uthread.h" 
#include <semaphore.h> 
#include <pthread.h> 
#ifndef STDIO_H_ 
#include <stdio.h> 
#endif 

namespace std { 
/* 
* Initializes all the variables and allocates memory when needed 
*/ 

int uthread::maxThreads; 
int uthread::currentThreads; 
pthread_mutex_t uthread::mapMutex; 
pthread_mutex_t uthread::qMutex; 
pthread_mutex_t uthread::threadMutex; 
map<int,UserThread*>* uthread::threadMap; 
priority_queue<UserThread*>* uthread::threadQueue; 

void uthread::uthread_init(int numKernelThreads) { 

    pthread_mutex_t tester; 
    pthread_mutex_init(&tester,NULL); 
    uthread::maxThreads=numKernelThreads; 
    uthread::currentThreads=0; 
    pthread_mutex_init(&threadMutex,NULL); 
    pthread_mutex_init(&qMutex,NULL); 
    pthread_mutex_init(&mapMutex,NULL); 
    threadQueue= new priority_queue<UserThread*>; 
    threadMap=new map<int,UserThread*>; 
} 
int uthread::uthread_create(void (* func)()) { 
    //Create ucontext to be used in in 
    ucontext_t* ucp=(ucontext_t*)malloc(sizeof(ucontext_t)); 
    getcontext(ucp); 
    ucp->uc_stack.ss_sp=(void*)malloc(16384); 
    ucp->uc_stack.ss_size=16384; 
    makecontext(ucp, func, 0); //make the context for a thread running func 
    //Create UserThread 
    time_t currTime; 
    time(&currTime); 
    UserThread* newThread=new UserThread(ucp,currTime); 
    //Thread Creation Logic 
    pthread_mutex_lock(&threadMutex); 
    if (currentThreads>=maxThreads) { 
     pthread_mutex_unlock(&threadMutex); 
     pthread_mutex_lock(&qMutex); 
     threadQueue->push(newThread); 
     pthread_mutex_unlock(&qMutex); 
     return 0; 
    } 
    else { 

     int (*execute)(void *)= (int (*)(void *)) func; 
     int tid=clone(execute,ucp->uc_stack.ss_sp,CLONE_VM|CLONE_FILES,NULL); 
     if (tid==-1) { //clone failed 
      pthread_mutex_unlock(&threadMutex); 
      return -1; 
     } 
     currentThreads++; 
     pthread_mutex_unlock(&threadMutex); 
     /* 
     * Map tid -> UserThread in thread map 
     */ 

     threadMap->insert(pair<int,UserThread*>(tid,newThread)); 
     pthread_mutex_unlock(&mapMutex); 
     return 0; 
    } 
    return -1; 
} 
void uthread::uthread_exit() { 
    /* 
    * Get the corresponding UserThread object from the map 
    */ 
    printf("Start Exit \n"); 
    int threadID=syscall(SYS_gettid) ; 
    pthread_mutex_lock(&mapMutex); 
    if (threadMap->find(threadID)==threadMap->end()) { //Cannot find map; 
     pthread_mutex_lock(&threadMutex); 
     currentThreads--; 
     pthread_mutex_unlock(&threadMutex); 
     exit(0); 
    } 
    printf("Getting Curr Thread\n"); 
    UserThread* currThread= threadMap->at(threadID); 
    pthread_mutex_unlock(&mapMutex); 
    pthread_mutex_lock(&qMutex); 

    if (threadQueue->empty()) { //No items on queue, delete memory references and exit 
     printf("Queue is Empty"); 
     pthread_mutex_unlock(&qMutex); 
     pthread_mutex_lock(&mapMutex); 
     threadMap->erase(threadID); 
     pthread_mutex_unlock(&mapMutex); 
     pthread_mutex_lock(&threadMutex); 
     currentThreads--; 
     pthread_mutex_unlock(&threadMutex); 
     delete currThread; 
     exit(0); 
    } 
    else { //Remove and delete memory reference to old thread, set context to new thread 
     printf("Swapping Queue\n"); 
     UserThread* newThread=threadQueue->top(); 
     threadQueue->pop(); 
     pthread_mutex_unlock(&qMutex); 
     pthread_mutex_lock(&mapMutex); 
     threadMap->insert(pair<int,UserThread*>(threadID,newThread)); //Update Map 
     pthread_mutex_unlock(&mapMutex); 
     printf("Deleting Current Thread\n"); 
     delete currThread; 
     printf("Setting Context\n"); 
     setcontext(newThread->ucp); 
     printf("set context failed\n"); 
    } 
} 
void uthread::uthread_yield() { 
    printf("Start Yield \n"); 
    int threadID=syscall(SYS_gettid) ; 
    pthread_mutex_lock(&mapMutex); 
    UserThread* currThread= threadMap->at(threadID); 
    pthread_mutex_unlock(&mapMutex); 
    pthread_mutex_lock(&qMutex); 
    if (threadQueue->empty()) { 
     printf("Queue is empty\n"); 
     pthread_mutex_unlock(&qMutex); 
     return; 
    } 
    else { 
     printf("Queue Not Empty\n"); 
     currThread->updateRuntime(time(NULL)); //updates run time account for time it's been on thread 
     UserThread* highestPriority=threadQueue->top(); 
     if (highestPriority->getRunTime()>currThread->getRunTime()) { //highestPriority is lower priority than currently running thread 
      printf("lowest runtime is running\n"); 

      pthread_mutex_unlock(&qMutex); 
      return; 
     } 
     else { 
      printf("SwapContext\n"); 
      threadQueue->pop(); 
      threadQueue->push(currThread); 
      pthread_mutex_unlock(&qMutex); 
      pthread_mutex_lock(&mapMutex); 
      threadMap->insert(pair<int,UserThread*>(threadID,highestPriority)); //Update Map reference 
      pthread_mutex_unlock(&mapMutex); 
      //Swaps contexts 
      swapcontext(currThread->ucp,highestPriority->ucp); 
      printf("Swapcontext Failed\n"); 
     } 

    } 

} 
int uthread::startThread(void* arg) { 
    printf("Thread Cloned\n"); 
    pthread_mutex_lock(&mapMutex); 
    int threadID=syscall(SYS_gettid) ; 
    UserThread* currThread= threadMap->at(threadID); 
    pthread_mutex_unlock(&mapMutex); 
    setcontext(currThread->ucp); 
    return 0; 

} 
} 

だ、これが私の対応UserThreadオブジェクトのコードです:

/* 
* UserThread.cpp 
* 
* Created on: Oct 12, 2016 
*  Author: michael 
*/ 

#include "UserThread.h" 
/* 
* Constructor. UCP is taken in as well as start time 
* Run time initialized to 0 
* 
*/ 
UserThread::UserThread(ucontext_t *ucp,time_t st) { 
    this->ucp=ucp; 
    this->startTime=(time_t*)malloc(sizeof(time_t)); 
    this->runTime=(double*)malloc(sizeof(double)); 
    *startTime=st; 
    *runTime=0; 

} 
/** 
* Deconstructor 
*/ 
UserThread::~UserThread() { 
    //free(ucp->uc_stack.ss_sp); 
    //free(ucp); 
    free(startTime); 
    free(runTime); 

} 
/* 
* adds the running time in seconds (as a double) to the current running time. Also updates the start time 
*/ 
void UserThread::updateRuntime(time_t currTime) { 
    double diffTime=difftime(currTime,*startTime); 
    *runTime=*runTime+diffTime; 
    *startTime=currTime; 
} 
/* 
* Just Updates the start time 
*/ 
void UserThread::updateStartTime(time_t newTime) { 
    *startTime=newTime; 
} 
/* 
* getter 
*/ 
double UserThread::getRunTime() { 
    double rTime=*runTime; 
    return rTime; 
} 
/* 
* getter 
*/ 
time_t UserThread::getStartTime() { 
    return *startTime; 
} 
/* 
* THIS IS REVERSED ON PURPOSE. C++ runs a maximum priority queue by default 
* by overloading the < operator backwards, that isn't an issue. Sketchy? Yes 
* Also functional 
*/ 
bool UserThread::operator <(UserThread* t2) { 
    return this->getRunTime() > t2->getRunTime(); 
} 

uthread_yield()が正しく失敗し、その後、各スレッドに対して一度に動作します。これがなぜなのか?私はこのコードを何時間も見つめていましたが、この時点ではアイデアはありません。

+0

デバッガを使用してみましたか?そして** CはC++と同じではありません** – amanuel2

+0

はい。それは私がswapcontextメソッドに入ることはできません。私はCがC++と同じではないことを知っていますが、C++コードでCライブラリを使用しています。 –

答えて

0

これは実際には失敗していません。エラーメッセージを表示しているだけです。 - しかし、そのスレッドが後で戻ってスワップされたとき、それはswapcontext()から戻って無条件のprintfを実行します()

swapcontext(currThread->ucp, highestPriority->ucp); 
printf("Swapcontext Failed\n"); 
結構です swapcontext()後の降伏スレッドスワップ離れそう

、:あなたの歩留まりの実装がで終了します。次のものが必要です。

if (swapcontext(currThread->ucp, highestPriority->ucp) == -1) { 
    printf("Swapcontext Failed\n"); 
    /* You need to fix up your queue and map here to account for the 
    * failure to context switch, and then probably loop back and look 
    * for another candidate thread to swap to. */ 
} 

私はまた、あなたのuthread_create()機能がマップにアクセスし、最初のミューテックスをロックせずにmapMutexのロックを解除することに気づきました。

pthreads関数は、サポートされていない裸のclone()システムコールと混合しています。基礎となるスレッドの管理にはpthread_create()/pthread_exit()を使用してください。これを行う1つの方法は、あなたのキューから実行するスレッドを引っ張るスケジューリング機能でpthread_create()開始によって作成されたスレッド持つことである。

void* uthread::newThread(void* arg) 
{ 
    pthread_mutex_lock(&qMutex); 

    if (threadQueue->empty()) { 
     printf("No thread to start.\n"); 
     return NULL; 
    } 

    UserThread* highestPriority = threadQueue->top(); 
    threadQueue->pop(); 
    pthread_mutex_unlock(&qMutex); 

    int threadID = syscall(SYS_gettid); 

    pthread_mutex_lock(&mapMutex); 
    threadMap->insert(pair<int,UserThread*>(threadID,highestPriority)); //Update Map reference 
    pthread_mutex_unlock(&mapMutex); 

    setcontext(highestPriority->ucp); 
    printf("setcontext() Failed\n"); 
    return NULL; 
} 

を...あなたはuthread_create()を簡素化することができ、常に新しいユーザーをプッシュキューにスレッド、および条件付きでのみ根底にあるスレッドの作成:ところで

// ... start of uthread_create() up to creating new UserThread ... 

pthread_mutex_lock(&qMutex); 
threadQueue->push(newThread); 
pthread_mutex_unlock(&qMutex); 

//Thread Creation Logic 
pthread_mutex_lock(&threadMutex); 
if (currentThreads < maxThreads) { 
    pthread_t new_pthread; 
    if (pthread_create(*new_pthread, NULL, uthread::newThread, NULL) != 0) { 
     printf("New pthread creation failed.\n"); 
    } else { 
     currentThreads++; 
    }   
} 
pthread_mutex_unlock(&threadMutex); 

return 0; 

を、あなただけのスレッドローカルストレージを実装する方法として、threadMapを使用しているようだ:あなたの代わりに使用することができます組み込みのpthreadsスレッドローカルストレージAPI(pthread_key_create()/pthread_setspecific()/pthread_getspecific())。

関連する問題