https://github.com/naghim/fft-lab13
https://github.com/naghim/fft-lab13
Last synced: 11 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/naghim/fft-lab13
- Owner: naghim
- Created: 2023-03-28T08:01:51.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-05-22T20:26:07.000Z (over 1 year ago)
- Last Synced: 2025-01-08T02:52:47.496Z (about 1 year ago)
- Size: 3.05 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Labor 13
## Threadek
Qt-ban lehetőségünk adódik a processzorunkat teljes mértékben kihasználni párhuzamos szálak segítségével. Qt-ban az erre használható osztály a QThread osztály. A QThread egy absztrakt osztály, amit származtatnunk kell, és implementálnunk kell a QThread::run() függvényét. Ez lesz az a függvény, ami végrehajtásra kerül a párhuzamos szál elinditása után. Egy párhuzamos szálat a QThread::start() függvénnyel indíthatunk el. Vigyázzunk arra, hogy a threadet ne a `run` függvénnyel, hanem a `start` függvénnyel indítsuk el. Ha a `run` függvénnyel indítjuk, ugyanazon a szálo fog futni, mint a felhasználói felület (GUI thread).
A QThread akkor is hasznos, hogyha a háttérben szeretnénk valamit futtatni. Ha egy kódrészletet egy QThread-ben indítunk el, az egy teljesen független szálon fog futni a felhasználói felülettől. Ha egy hosszabb kódot elindítunk simán a Qt-ből, akkor le fogja fagyasztani a felületet. Ha QThread-ből indítjuk, akkor, mivel a háttérben fut egy teljesen más szálon, nem fogja befolyásolni a felület futtatását, vagyis responsive marad a felület.
Egy QThread-en belül sajnos nem tudjuk módosítani a felület kinézetét. Például nem tudunk hozzáférni a felület komponenseihez. Ha például egy progress bárt szeretnénk frissíteni, azt közvetlenül a threadből nem tudjuk. Emiatt szükséges a signal-slot mechanizmus használata. A QThread képes küldeni egy signal-t, amit kifoghatunk a felhasználói felület részéről egy megfelelő slottal. Például:
```cpp
class WorkerThread : public QThread {
Q_OBJECT
public:
void run() override;
signals:
void progressUpdated(int value);
};
void WorkerThread::run() {
// Hosszabb időt felvevő kód futtatása...
// ...
// Frissítsük a felületet signal segítségével
emit progressUpdated(50);
}
```
illetve:
```cpp
class MainWindow : public QMainWindow {
Q_OBJECT
private slots:
void onProgressUpdated(int value);
private:
void startThread();
};
void MainWindow::onProgressUpdated(int value) {
// Az esemény feldolgozása
this->progressBar->setValue(progress);
}
void MainWindow::startThread() {
WorkerThread *thread = new WorkerThread;
// Feliratkozás az eseményre
connect(thread, &WorkerThread::progressUpdated, this, &MainWindow::onProgressUpdated);
// A szál konkrét elindítása
thread->start();
}
```
## Feladatok
1. Készítsünk egy programot amely segítségével a felhasználó egy fájlban található számok közül meg tudja keresni a leghosszabb Collatz-pályát.
A **Collatz-sejtés** a következőket mondja ki: vegyünk egy tetszőleges pozitív egész számot és a következő műveleteket egymás után hajtsuk végre rajta, a végén mindig 1-hez érünk:
- ha a szám páros, osszuk el kettővel;
- ha a szám páratlan, háromszorozzuk meg, és adjunk hozzá egyet.
Vagyis a következő képlettel írhatjuk ezt le:

**Collatz-pályának** nevezzük azt a számszekvenciát, amelyet az adott számtól kiindulva, elvégezve a műveleteket kapunk egészen az 1-ig bezárólag. A lépések/számok darabszáma a pálya hossza.
_Például_:
`7` esetén a pálya a következőképp alakul:
`7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1`.
A szekvencia hossza pedig: `16`.
A felület adjon lehetőséget a felhasználónak kiválasztani egy állományt (használjunk QFileDialog-ot), amely pozitív egész számokat tartalmaz (lásd `numbers.txt` a labor fájljai között). A Process gombra kattintva kapcsoljuk ki a felület gombjait, és indítsunk `N` darab (`N` a CPU magok száma) párhuzamos szálat (lásd QThread). A szálak között osszuk fel a beolvasott számokat, hogy mindegyik szál ugyanannyi számot dolgozzon fel:
```cpp
int numThreads = std::thread::hardware_concurrency();
std::vector threads;
int chunkSize = numbers.size() / numThreads;
for (int i = 0; i < numThreads; ++i) {
int start = i * chunkSize;
int end = (i == numThreads - 1) ? numbers.size() : start + chunkSize;
std::vector chunk(numbers.begin() + start, numbers.begin() + end);
WorkerThread *thread = new WorkerThread(chunk);
connect(thread, &WorkerThread::progressUpdated, this, &MainWindow::onProgressUpdated);
connect(thread, &WorkerThread::newLongestPathFound, this, &MainWindow::onNewLongestPathFound);
threads.push_back(thread);
}
```
Mindegyik szál felelős a neki kiosztott számok Collatz-pályájának kiszámításáért. Minden 100 szám kipróbálása után emitteljen egy `progressUpdated` nevű signált, amelyet felfog az ablakunk és frissíti a rajta lévő progress bárt. Amennyiben kapunk egy új leghosszabb Collatz-pályát értesítsük az ablakot a `newLongestPathFound` signállal. Ha az összes számot kipróbáltuk, akkor oldjuk fel a felületen található gombokat, hogy lehessen újrapróbálni a számítást. Vigyázzunk arra, hogy az utolsó száz vagy kevesebb számot is lejelentsük miután feldolgoztuk őket.
