ОС1/Модификације фебруар 2023
Следеће модификације су се појавиле на одбрани пројекта у фебруарском року 2023.
Могли сте да изабере да радите или 1. модификацију или 2. модификацију.
Модификација без асинхроне промене контекста
- Додати системски позив чија је декларација
void thread_join(thread_t* handle)који текућу нит зауставља док се не заврши извршавање нити означене ручкомhandle. У оквиру C++ АПИ додати нестатичку методу класиThreadса декларацијомvoid join(). Написати тест програм користећи C++ АПИ са три нити, где ће једна нит чекати да се заврше друге две. Свака нит на почетку исписује поруку која је то нит, затим ради неку обраду(имплементирати угњежденим петљама) и на крају исписује поруку да се завршила.
Решење
сyсцалл_ц.хпп
class TCB;
typedef TCB* thread_t;
void thread_join(thread_t* handle);
сyсцалл_ц.цпп
void thread_join(thread_t* handle)
{
uint64 number = 0x03; // Mogao je bilokoji, slobodan, ulaz
__asm__ volatile("mv a1, %0" : : "r" (handle));
__asm__ volatile("mv a0, %0" : : "r" (number));
__asm__ volatile("ecall");
}
ТЦБ.хпп
typedef TCB* thread_t;
class TCB
{
public:
// ...
private:
// ...
static void join (thread_t* handle);
// ...
};
ТЦБ.цпп
/* Glavni deo resenja */
void TCB::join(thread_t* handle)
{
while(!(*handle)->isFinished())
TCB::dispatch();
}
рисцв.цпп
case 0x03: // Mogao je bilokoji, slobodan, ulaz
{
thread_t *handle;
__asm__ volatile ("mv %0, a1" : "=r" (handle));
TCB::join(handle);
break;
}
сyсцалл_цпп.хпп
class Thread
{
public:
// ...
void join(); // Obavezno nestaticka metoda
protected:
// ...
private:
thread_t myHandle; // Ovo je vec postojalo
};
сyсцалл_цпп.цпп
void Thread::join()
{
if (myHandle)
thread_join(&myHandle);
}
маин.цпп
#include "../h/syscall_cpp.hpp"
bool finishedA = false;
bool finishedB = false;
class WorkerA: public Thread
{
void mod_fun_A(void* arg);
public:
WorkerA():Thread() {}
void run() override
{
mod_fun_A(nullptr);
}
};
class WorkerB: public Thread
{
void mod_fun_B(void* arg);
public:
WorkerB():Thread() {}
void run() override
{
mod_fun_B(nullptr);
}
};
void WorkerA::mod_fun_A(void *arg)
{
for (uint64 i = 0; i < 10; i++)
{
printString("A: i=");
printInt(i);
printString("\n");
for (uint64 j = 0; j < 10000; j++)
{
for (uint64 k = 0; k < 30000; k++)
{
/* busy wait */
}
thread_dispatch();
}
}
printString("A finished!\n");
finishedA = true;
}
void WorkerB::mod_fun_B(void *arg)
{
for (uint64 i = 0; i < 16; i++)
{
printString("B: i=");
printInt(i);
printString("\n");
for (uint64 j = 0; j < 10000; j++)
{
for (uint64 k = 0; k < 30000; k++)
{
/* busy wait */
}
thread_dispatch();
}
}
printString("B finished!\n");
finishedB = true;
thread_dispatch();
}
int main()
{
Riscv::w_stvec((uint64) &Riscv::supervisorTrap);
Thread* main = new Thread(nullptr, nullptr);
printString("Main Created\n");
TCB::running = main->getMyHandle();
/* Modifikacija */
Thread* threads[2];
threads[0] = new WorkerA();
printString("ThreadA created\n");
threads[1] = new WorkerB();
printString("ThreadB created\n");
for(int i = 0; i < 2; i++)
threads[i]->start();
threads[0]->join(); // Blokiraj main nit(u ovom slucaju) dok se nit 0 ne zavrsi
threads[1]->join(); // Blokiraj main nit(u ovom slucaju) dok se nit 1 ne zavrsi
for (auto thread: threads)
delete thread;
printString("Main Stopped\n");
return 0;
}
Додатно
Додатно, приликом испитивања, тражили су да нит А чека да се заврши нит Б. У том случају морали смо ово:
threads[0] = new WorkerA();
printString("ThreadA created\n");
threads[1] = new WorkerB();
printString("ThreadB created\n");
for(int i = 0; i < 2; i++)
threads[i]->start();
да дефинисемо глобално у фајлу "маин.цпп" и да након креирања маин-а, одмах урадимо диспатцх.
А онда да унутар функције "мод_фун_А", ставимо:
threads[1]->join();
тхреадс[1] је нит Б.
Модификација са асинхроном променом контекста
- Додати ситемски позив чија је декларација
void thread_join(thread_t* handle, time_t t)који текућу нит зауставља док се не заврши извршавање нити означеном ручкомhandleуколико јеtједнако нули, а уколико јеtвеће од нуле онда се текућа нит зауставља максималноtвремена или краће уколико се нит означена саhandleзаврши. У оквиру C++ АПИ додати методу класиThreadса декларацијомvoid join(time_t).
Написати тест програм користећи C++ АПИ са три нити, где ће две нити чекати да се заврши трећа нит, али једна треба да чека максимално неко време t, а друга док се заиста не заврши трећа нит. Трећа нит треба да траје довољно дуго како би се испољило описано понашање. Свака нит на почетку исписује поруку која је то нит, затим ради неку обраду(имплементирати угњежденим петљама) и на крају исписује поруку да се завршила. Додатно, нит која чека максимално t времена треба након што истекне то време да испише поруку да је наставила извршавање.