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()
が正しく失敗し、その後、各スレッドに対して一度に動作します。これがなぜなのか?私はこのコードを何時間も見つめていましたが、この時点ではアイデアはありません。
デバッガを使用してみましたか?そして** CはC++と同じではありません** – amanuel2
はい。それは私がswapcontextメソッドに入ることはできません。私はCがC++と同じではないことを知っていますが、C++コードでCライブラリを使用しています。 –