Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 06.03.2019
Сообщений: 55

Создать и разбить одномерный массив на m одинаковых интервалов с использованием опций shared, private директивы parallel

23.09.2020, 19:01. Показов 2615. Ответов 22

Студворк — интернет-сервис помощи студентам
Не могу понять, как нужно правильно решить задачу, помогите кто шарит.

Дан одномерный массив A из n случайных элементов, расположенный в
общей памяти. Массив разделен на m одинаковых интервалов (по
количеству нитей). Каждая нить создает в локальной памяти массив B из
n/m элементов и копирует в массив B элементы из заданного интервала
массива A. Результат выводится на экран (в файл). (Примечание:
использование опций shared, private директивы parallel).
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.09.2020, 19:01
Ответы с готовыми решениями:

Какой View лучше "shared, Private On First Use" или Shared
Доброго всем дня. Вопрос больше теоретически. Есть набор документов (пока немного около 500, каждый месяц будет прирост примерно...

Как разбить массив на 10 интервалов?
Здравствуйте. Есть массивResult: array of integer. Как его разбить на 10 интервалов?

Shared Private On First Use
В базе есть SPOFU фолдер SearchPersons. При попытке добавить документы в этот фолдер var c:NotesDocumentCollection =...

22
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
29.09.2020, 16:54
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Earmag Посмотреть сообщение
Ошибки на скрине.
В свойствах проекта, в Gentral->С++ Languge Standard поставь который latest
0
377 / 228 / 79
Регистрация: 24.11.2009
Сообщений: 695
30.09.2020, 03:27
Ок.
Во первых, предлагаю отказаться от заполнения массива случайными числами, и наполнить его целыми по возрастанию - так будет проще контролировать работу потоков.
Во вторых, короткое замечания о работе openMP:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// все переменные объявленные до parallel автоматически shared
int a[20]; // shared.
#pragma omp parallel 
{
    // скоуп после parallel выполняется в каждом треде.
    // все переменные объявленные после parallel автоматически private - локальные.
    // (есть исключения, но не в этой программе).
    int b[5]; //private
    #pragma omp for 
    for (int i = a; i<b; i++)
    {
        // итерации цикла будет поделены между потоками каким-то образом на усмотрение 
        // компилятора и/или кода библиотеки. Часто(но не обязательно) по принципу - освободившийся поток
        // получает следующую по порядку итерацию
    }
    #pragma omp for schedule(static)
    {
        // То же самое, но теперь мы явно определяем каким образом будут поделены итерации
        // между потоками. Если оставить остальные аргументы шедулера по умолчанию. 
        // Компилятор подберет размер задач для потоков таким образом, чтобы каждый поток выполнил 
        // примерно равный набор итераций идущих подряд. То есть, то что нужно ТС-у (почти*).
    }
    #pragma omp critical
    {
        // некоторые операции работают с общими ресурсами, например, вывод консоли - потоки будут 
        // конкурировать за них. я не понмю, является ли printf() потокобезопасным, но поскольку 
        // всё равно придется выводить массив в цикле, придется объявить critical секцию.
        // пока выполняется critical одного потока - остальные не входят в свою.
    }
}
так же библиотека предоставляет ряд интересных функций:
C++
1
2
3
int omp_get_max_threads() // узнать количество потоков процессора
void omp_set_num_threads(int n) // задать количество потоков в программе
int omp_get_thread_num() // узнать номер текущего потока.
Добавлено через 26 минут
В принципе, этого достаточно, чтобы решить задачу. Но нужно еще рассмотреть ситуацию с почти*. Суть проблемы в том, что в случае, если количество элементов в А не кратно количеству потоков, часть потоков получит меньше итераций и должно иметь меньшую размерность массива В. А ТС не хочет использовать динамически расширяющиеся контейнеры. Размерность массива B можно определить, узнав распределение итераций для тредов, но только в цикле for. Можно замутить замыкание или функтор, но видимо, этот вариант отпадает по той же причине, по которой отпал вектор. Можно посчитать руками на основе спецификации OpenMP. И наконец, видимо, можно использовать динамический массив СИ, постоянно делая realloc при добавлении элементов, либо выделив память под него в самой первой итерации цикла и проверяя, что память выделена во всех последующих.
С другой стороны, можно отказаться от распараллеливания omp for и определить диапазоны индексов А в каждом треде самостоятельно на основе номера треда. Создать массивы В и скопировать данные из соответствующего диапазона А.

Добавлено через 4 часа 46 минут
С потоками кратными размеру массива:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int main() {
    const int a_size = 20; //размер исходного массива A.
 
    int A[a_size];
    for (int i = 0; i < a_size; i++) A[i] = i + 1;
 
    printf("array A[%d] = [", a_size);
    for (int i = 0; i < a_size; i++) printf(" %02d", A[i]);
    printf(" ]\n");
    
    int m = 4; //количество параллельных потоков.
    omp_set_num_threads(m);
 
    //параллельная секция, shared(A) не нужен, но была просьба его использовать.
#pragma omp parallel  shared(A)
    {
        //все объявления ниже - приватны.
        int b_size = a_size / omp_get_num_threads(); // размер локального массива B
        
        int* b = (int*)malloc(sizeof(int) * b_size);
        int* first = &A[0] + omp_get_thread_num() * b_size; // первый элемент в интервале копирования для этого треда
        memcpy(b, first, b_size * sizeof(int));
 
#pragma omp critical
        {
            // здесь просто печать локального массива B.
            printf("thread %02d: ", omp_get_thread_num());
            printf("array B[%d] = [", b_size);
            for (int i = 0; i < b_size; i++) printf(" %02d", b[i]);
            printf(" ]\n");
        }
        free(b);
    }
}
0
377 / 228 / 79
Регистрация: 24.11.2009
Сообщений: 695
30.09.2020, 14:27
Ну и наконец, чтобы решить задачу для случая, когда количество итераций не кратно количеству потоков:
Пусть https://www.cyberforum.ru/cgi-bin/latex.cgi?n- количество итераций, https://www.cyberforum.ru/cgi-bin/latex.cgi?p - количество потоков,
представим
https://www.cyberforum.ru/cgi-bin/latex.cgi?n = q \cdot p +r , где https://www.cyberforum.ru/cgi-bin/latex.cgi?q =\lfloor {n}/{p} \rfloor, а https://www.cyberforum.ru/cgi-bin/latex.cgi?r - остаток от деления.

Для равномерного распределения задачи первые https://www.cyberforum.ru/cgi-bin/latex.cgi?r потоков получат https://www.cyberforum.ru/cgi-bin/latex.cgi?q+1 итераций, а последние https://www.cyberforum.ru/cgi-bin/latex.cgi?p-r потоков получат по https://www.cyberforum.ru/cgi-bin/latex.cgi?q операций.

C
1
2
3
4
5
6
7
            int p = omp_get_num_threads();
            int k = omp_get_thread_num();
 
            int q = a_size / p;
            int r = a_size % p;
 
            int b_size = q + ((k < r) ? 1 : 0);  // размер локального массива B
А поскольку первые и последние потоки получили разное количество элементов для копирования, то и в вычисление адреса первого элемента интервала k-го потока нужно ввести поправку:
C
1
2
            int* first = &A[0] + q * k;         // первый элемент в интервале копирования для этого потока
            if (k) first += ((k < r) ? k : (r));
так же, позволил себе обернуть код в while(true) для удобства демонстрации с различным количеством потоков.
решение для не кратного количества элементов
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int main() {
    const int a_size = 20; //размер исходного массива A.
 
    int A[a_size];
    for (int i = 0; i < a_size; i++) A[i] = i + 1;
 
    printf("array A[%d] = [", a_size);
    for (int i = 0; i < a_size; i++) printf(" %02d", A[i]);
    printf(" ]\n");
    
    int m = 4; //количество параллельных потоков.
 
    while (true)
    {
        printf("thread count? n = ");
        scanf_s("%d", &m);
        if (m<=0) break;
 
        omp_set_num_threads(m);             // устанавливаем количество потоков.
 
//параллельная секция, shared(A) не нужен, но была просьба его использовать.
#pragma omp parallel shared(A)
        {
            //все объявления ниже - приватны.
 
            int p = omp_get_num_threads(); // количество потоков
            int k = omp_get_thread_num();  // номер текущего треда
 
            int q = a_size / p;
            int r = a_size % p;
 
            int b_size = q + ((k < r) ? 1 : 0);  // размер локального массива B
 
            int* first = &A[0] + q * k;         // первый элемент в интервале копирования для этого потока
            if (k) first += ((k < r) ? k : (r));
 
            int* b = (int*)malloc(sizeof(int) * b_size); // локальный массив B;
 
            memcpy(b, first, b_size * sizeof(int));
 
#pragma omp critical
            {
                // здесь просто печать локального массива B.
                printf("thread %02d: ", omp_get_thread_num());
                printf("array B[%d] = [", b_size);
                for (int i = 0; i < b_size; i++) printf(" %02d", b[i]);
                printf(" ]\n");
            }
            free(b);
        }
    }
}
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
30.09.2020, 14:27

Shared, Private On First Use Folder
Я использую Shared, private on first use folder для сортировки коллекции вообщем-то Так вот, если у юзера не стоит галочка Create...

Как обновлять Shared, Private On First Use
Всем доброго времени суток. Для отбора личных документов использую вид Shared, private on first use в формуле отбора пишу следующий...

Shared, Desktop Private On First Use Folder
Доброго времени суток. Не могу получить Shared, desktop private on first use folder Dim folder As NotesView Set folder =...

Вопрос по Shared, Private-on-first-usе Views
Подскажите, пожалуйста, как решить следующую проблему. Есть View, определенное как Shared, private-on-first-usе. Через некоторое время...

Помогите плиз! Баг с Shared, Private-on-first-use View
Всем привет! Помогите плиз: Есть Shared, private-on-first-use view. Есть документы пользователей. По идее надо, чтобы работало так: ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
23
Ответ Создать тему
Новые блоги и статьи
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
Генератор паролей (вариант №4)
Maks 01.11.2026
После публикации 3-го варианта генератора паролей, разослал его своим коллегам (с целью оценки), в итоге были получены следующие рекомендации: 1. Вернуть возможность использования знаков | 1 l I;. . .
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
Генератор паролей (вариант №2)
Maks 30.10.2026
Обновленная версия ранее созданной обработки. Добавлены следующие реквизиты типа Булево: - Буквы; - Цифры; - Символы. Изменена логика команды "Сгенерировать" и процедуры "ПриОткрытии":. . .
Генератор паролей (вариант №1)
Maks 29.10.2026
Реализация из решения ниже выполнена исключительно по моей инициативе, дабы облегчить себе работу в создании паролей для администрируемых мною сервисов и пользователей. Самым главным критерием для. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru