Может ли многопоточная функция использовать статический массив для обмена данными между потоками? - PullRequest
2 голосов
/ 12 февраля 2011

Скажем, у вас есть функция, которая подсчитывает вхождения значения в большой массив.Вы хотите многопоточность этой функции, чтобы каждый поток подсчитывал вхождения в своей части массива, а затем суммировал результаты.Можно предположить, что каждый поток имеет уникальный ранг (от 0 до N-1), и что каждый поток будет вызывать функцию примерно в одно и то же время.Например:

int count[N];  // global array

int countOccurences()
{
    count[rank] = /* count occurences in one part of the array */
    // wait until all other threads reached this point
    int total = 0;
    for (int i=0; i<N; i++)
        total += count[i];
    return total;
}

Вопрос в приведенном выше примере: можно ли переместить массив count в тело countOccurences() в качестве статической переменной?Мне не нужно, чтобы он существовал где-либо за пределами тела функции: будет ли статический массив разделен между потоками?

Ответы [ 2 ]

2 голосов
/ 12 февраля 2011

Ответ на ваш вопрос - да, потоки имеют доступ к глобальным и статическим данным в одном модуле компиляции, но есть еще кое-что в этой теме об «обмене данными между потоками», которую важно понять.

Для каждого потока существует соответствующая функция («функция потока»), которую поток будет выполнять параллельно с другими потоками. Поток имеет доступ ко всему, к чему эта функция имеет доступ, через указатель или опорные параметры, глобальные данные, статические данные в том же модуле компиляции, что и функция потока, или глобальные и / или статические данные, которые доступны для чтения / изменения через другие функции, функция потока может вызвать. Вы должны быть в состоянии определить каждую область памяти, которую данная функция может прочитать или изменить. Эти области памяти данной функции потока являются точно областями памяти, к которым у потока есть доступ.

Легко видеть, что глобальные данные и статические данные в одном модуле компиляции доступны для функции потока, поэтому ответ на ваш вопрос "да".

Одна вещь, на которую вы можете обратить внимание, - это OpenMP, который имеет встроенные конструкции для распараллеливания операции countOccurrences (так называемое «сокращение»):

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

size_t countOccurrences(const int *arr, size_t n, int which) {
    size_t count, i;

    count = 0;

    #pragma omp parallel for reduction(+:count)
    for (i = 0; i < n; ++i) {
        if (arr[i] == which)
            ++count;
    }

    return count;
}

int main()
{
    int arr[] = { 3, 5, -1, -1, 0 };

    size_t count = countOccurrences(arr, sizeof (arr)/sizeof (arr[0]), -1);
    printf("count = %d\n", (int) count);
    return EXIT_SUCCESS;
}
2 голосов
/ 12 февраля 2011

Да, вы можете, потому что ваши потоки заканчивают свою работу, прежде чем вы вернетесь из своего countOccurences.просто передайте ссылку на i-й элемент в функцию i-го потока, чтобы он мог получить к нему доступ

примерно так:

#include <boost/thread.hpp>
#include <numeric>
#include <boost/bind.hpp>

void thread_function(int& result)
{
    // your implementation
}

size_t const n = 100;

int countOccurences()
{
    int count[n];
    boost::thread_group group;
    for (int i = 0; i != n; ++i)
        group.create_thread(boost::bind(thread_function, boost::ref(count[i])));
    group.join_all();
    return std::accumulate(count, count + n, 0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...