ОС1/Модификације октобар 2025
Модификација: јоинАлл (30п)
Доодати системске позиве thread_add_child и thread_join_all.
thread_add_child региструје дете-нит за текућу (позивајућу) нит.
thread_join_all блокира текућу нит док се сва њена деца не изврше.
У оквиру C++ АПИ додати нестатичке методе addChild(Thread* child) и joinAll() у класу Thread.
Написати тест програм: нит А прави 3×Б и 1×Ц, сваки Б прави 3×Ц. Родитељ чека сву своју децу пре него што настави.
Решење
ТЦБ.хпп
Додато на врху фајла (форwард децларатион):
class Semaphore;
Нова поља у private секцији:
TCB* parent; // pokazivač na roditelja (nullptr ako nema)
int childCount; // broj nezavršene dece
Semaphore* childrenSem; // semafor na koji roditelj čeka u joinAll
Нове методе у public секцији:
static void addChild(TCB* parent, TCB* child);
static void joinAllChildren();
ТЦБ.цпп
Додат инцлуде на врху:
#include "../h/Semaphore.hpp"
У конструктору, иницијализација нових поља (после this->finished = false;):
this->parent = nullptr;
this->childCount = 0;
this->childrenSem = nullptr;
Измењен dispatch() — елсе грана проширена да обавести родитеља кад дете заврши:
void TCB::dispatch() {
TCB *old = running;
if (!old->isFinished()) {
Scheduler::put(old);
} else {
if (old->parent != nullptr) {
old->parent->childCount--;
if (old->parent->childCount == 0 && old->parent->childrenSem != nullptr) {
old->parent->childrenSem->sem_signal();
}
}
}
running = Scheduler::get();
contextSwitch(&old->context, &running->context);
}
Нове функције:
void TCB::addChild(TCB* parent, TCB* child) {
child->parent = parent;
parent->childCount++;
if (parent->childrenSem == nullptr) {
Semaphore::createSemaphore(&parent->childrenSem, 0);
}
}
void TCB::joinAllChildren() {
if (running->childCount <= 0) return;
running->childrenSem->sem_wait();
}
сyсцалл_ц.хпп
Додате декларације:
void thread_add_child(thread_t child);
void thread_join_all();
сyсцалл_ц.цпп
void thread_add_child(thread_t child) {
if (child == nullptr) return;
do_syscall(0x16, (uint64)child);
}
void thread_join_all() {
do_syscall(0x17);
}
РИСЦВ.цпп (хандлеСупервисорТрап)
Додате нове цасе гране у сwитцх (после цасе 0x13 диспатцх):
case 0x16: {
TCB *child = (TCB*)arg1;
TCB::addChild(TCB::running, child);
break;
}
case 0x17: {
TCB::joinAllChildren();
break;
}
сyсцалл_цпп.хпп
Додате методе у класу Thread (публиц секција):
void addChild(Thread* child);
void joinAll();
сyсцалл_цпп.цпп
void Thread::addChild(Thread* child) {
thread_add_child(child->getMyHandle());
}
void Thread::joinAll() {
thread_join_all();
}
Тест пример
#include "../h/syscall_cpp.hpp"
#include "../h/syscall_c.hpp"
#include "../h/printing.hpp"
class ThreadC : public Thread {
public:
ThreadC(int id) : Thread(), id(id) {}
private:
int id;
void run() override {
printString(" C");
printInt(id);
printString(" started\n");
volatile int sum = 0;
for (int i = 0; i < 3000; i++)
for (int j = 0; j < 3000; j++)
sum += j;
printString(" C");
printInt(id);
printString(" finished\n");
}
};
class ThreadB : public Thread {
public:
ThreadB(int id) : Thread(), id(id) {}
private:
int id;
void run() override {
printString(" B");
printInt(id);
printString(" started, creating 3 C children\n");
ThreadC* c[3];
for (int i = 0; i < 3; i++) {
c[i] = new ThreadC(id * 10 + i);
c[i]->start();
this->addChild(c[i]);
}
printString(" B");
printInt(id);
printString(" waiting for children...\n");
this->joinAll();
printString(" B");
printInt(id);
printString(" all children done!\n");
for (int i = 0; i < 3; i++) delete c[i];
}
};
void joinAllTest() {
printString("A started, creating 3 B and 1 C\n");
ThreadB* b[3];
for (int i = 0; i < 3; i++) {
b[i] = new ThreadB(i);
b[i]->start();
thread_add_child(b[i]->getMyHandle());
}
ThreadC* c = new ThreadC(99);
c->start();
thread_add_child(c->getMyHandle());
printString("A waiting for all children...\n");
thread_join_all();
printString("\n=== A: ALL children done! ===\n");
for (int i = 0; i < 3; i++) delete b[i];
delete c;
}
Напомена: start() мора бити позван ПРЕ addChild() јер start() интерно позива thread_create() који поставља myHandle. Без тога, getMyHandle() враћа nullptr.
Очекиван оутпут
A started, creating 3 B and 1 C
A waiting for all children...
B0 started, creating 3 C children
B0 waiting for children...
B1 started, creating 3 C children
B1 waiting for children...
B2 started, creating 3 C children
B2 waiting for children...
C99 started
C99 finished
C0 started
C0 finished
C1 started
C1 finished
...svi C završe...
B0 all children done!
B1 all children done!
B2 all children done!
=== A: ALL children done! ===
Како ради
Сваки ТЦБ има поље parent (ко је родитељ) и childCount (колико деце још ради). Родитељ се блокира на семафору (childrenSem, иницијално 0). Кад нит заврши, у dispatch() се декрементира parent->childCount. Тек кад последње дете спусти бројач на 0, позива се sem_signal() који деблокирара родитеља.