Я улучшаю свой код, основываясь на комментариях и ответах на мой вопрос В результате, последовательная обработка для игры в жизнь работает, как показано ниже.
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int neighbor = countNeighbors(gamefieldSerial, i, j, width, height);
if (gamefieldSerial[i][j] == DEAD) {
if (neighbor == 3) {
gamefieldBuffer[i][j] = LIVE;
}
}
else if (gamefieldSerial[i][j] == LIVE) {
if (neighbor < 2 || neighbor > 3) {
gamefieldBuffer[i][j] = DEAD;
}
}
}
}
copyField(gamefieldBuffer, gamefieldSerial, width, height);
countNeighbors()
просто считает живые ячейки вокруг текущей ячейки (которая является gamefieldSerial [i] [j]) и возвращается. int** gamefieldBuffer
для написания нового поколения игрового поля и copyField()
для его применения ( Отделение старого состояния от нового состояния , это было очень полезно).
И в параллельной обработке это идет как ниже (например, мое поле 512 * 512). Я думаю, что каждый поток (4) занимает четверть поля (gamefieldParallel
) и использует gamefieldBuffer1, gamefieldBuffer2, gamefieldBuffer3, gamefieldBuffer4
(что точно так же, как gamefieldBuffer
), чтобы написать новое поколение четверти игрового поля и применить его с for-l oop.
#pragma omp parallel num_threads(4)
{
#pragma omp sections firstprivate(gamefieldParallel)
{
#pragma omp section
{
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
int neighbor = countNeighbors(gamefieldParallel, i, j, width, height);
if (gamefieldParallel[i][j] == DEAD) {
if (neighbor == 3) {
gamefieldBuffer1[i][j] = LIVE;
}
}
else if (gamefieldParallel[i][j] == LIVE) {
if (neighbor < 2 || neighbor > 3) {
gamefieldBuffer1[i][j] = DEAD;
}
}
}
}
}
#pragma omp section
{
for (int i = 0; i < 256; i++) {
for (int j = 256; j < 512; j++) {
int neighbor = countNeighbors(gamefieldParallel, i, j, width, height);
if (gamefieldParallel[i][j] == DEAD) {
if (neighbor == 3) {
gamefieldBuffer2[i][j] = LIVE;
}
}
else if (gamefieldParallel[i][j] == LIVE) {
if (neighbor < 2 || neighbor > 3) {
gamefieldBuffer2[i][j] = DEAD;
}
}
}
}
}
#pragma omp section
{
for (int i = 256; i < 512; i++) {
for (int j = 0; j < 256; j++) {
int neighbor = countNeighbors(gamefieldParallel, i, j, width, height);
if (gamefieldParallel[i][j] == DEAD) {
if (neighbor == 3) {
gamefieldBuffer3[i][j] = LIVE;
}
}
else if (gamefieldParallel[i][j] == LIVE) {
if (neighbor < 2 || neighbor > 3) {
gamefieldBuffer3[i][j] = DEAD;
}
}
}
}
}
#pragma omp section
{
for (int i = 256; i < 512; i++) {
for (int j = 256; j < 512; j++) {
int neighbor = countNeighbors(gamefieldParallel, i, j, width, height);
if (gamefieldParallel[i][j] == DEAD) {
if (neighbor == 3) {
gamefieldBuffer4[i][j] = LIVE;
}
}
else if (gamefieldParallel[i][j] == LIVE) {
if (neighbor < 2 || neighbor > 3) {
gamefieldBuffer4[i][j] = DEAD;
}
}
}
}
}
} // end of sections
} // end of parallel
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 256; j++) {
gamefieldParallel[i][j] = gamefieldBuffer1[i][j];
}
}
for (int i = 0; i < 256; i++) {
for (int j = 256; j < 512; j++) {
gamefieldParallel[i][j] = gamefieldBuffer2[i][j];
}
}
for (int i = 256; i < 512; i++) {
for (int j = 0; j < 256; j++) {
gamefieldParallel[i][j] = gamefieldBuffer3[i][j];
}
}
for (int i = 256; i < 512; i++) {
for (int j = 256; j < 512; j++) {
gamefieldParallel[i][j] = gamefieldBuffer4[i][j];
}
}
По этой причине я попытался следовать этим советам.
- Отделить старое состояние от нового: поэтому я использую несколько полей .
- Все ваши потоки могут с радостью делиться старым состоянием (потому что никто не меняет его во время итерации): firstprivate (), чтобы дать каждому потоку копию игрового поля.
- Разбейте работу на чанки - по одному для каждого потока. Итак, я разделил его на части.
- Дайте каждому потоку отдельный кусок памяти для хранения его результатов. То есть gamefieldBuffer1, 2, 3, 4.
- Раз все Темы закончены, у вас есть основной поток, объединяющий все их результаты в одном новом игровом поле. Это сделано для -l oop.
И результат был положительным. Я имею в виду, что определенно было некоторое ускорение для последовательного и параллельного обоих , но параллель все же медленнее последовательного. Я думаю, что где-то есть ошибки или ошибки, но я не могу их найти. Это моя первая проблема.
Мой второй вопрос: когда я устанавливаю num_threads () в параллельном регионе как 1, а не 4, почему это быстрее, чем последовательная обработка. результат с 4 потоками результат с 1 потоком С изображением выше 4 потока немного быстрее, чем последовательный, но в большинстве случаев он медленнее, чем последовательный.
Я думал использование 1 потока в многопоточности равнозначно однопоточности, но это не так? Я не привык к многоядерному программированию (или многопоточности? что-то с использованием openmp ..: p), чему я учусь в школе в этом семестре. Может я что то не так знаю, верно? Может кто-нибудь сообщить мне об этом?
Спасибо.