Windows 8: Написание многопоточных приложений для магазина Windows с помощью Intel® Threading Building Blocks

Источник: habrahabr
vpolin

Как известно, в программном интерфейсе приложений для магазина Windows (Windows Store apps) отсутствуют многие функции работы с потоками, начиная с CreateThread() и заканчивая работой с TLS ключами. И это отличный повод перейти от параллелизма, основанного на системно-зависимых потоках к параллелизму, основанному на задачах. Данный пост излагает пошаговую инструкцию о том, как написать простейший многопоточный пример, который проходит аттестацию для магазина Windows (Windows App Certification Kit validation) и, гипотетически, может быть масштабирован до игрушек космического масштаба. А поскольку используется кроссплатформенная библиотека Intel® Threading Building Blocks (Intel® TBB, TBB, threadingbuildingblocks.org), то вычислительная часть может быть легко перенесена на другие платформы, и задача будет заключаться только в том, чтобы нарисовать новый красивый графический интерфейс. 

В недавно вышедшем релизе библиотеки Intel® TBB tbb41_20121112oss, который доступен для загрузки на нашем сайте threadingbuildingblocks.org, добавлена экспериментальная поддержка приложений для магазина Windows, т.е. использование только разрешенного программного интерфейса для разработки таких приложений. 
И так, что же необходимо сделать, чтобы собрать простое приложение с использоанием Intel TBB.
Для начала необходимо распаковать и откомпилировать библиотеку, поскольку этот релиз распространяется только в исходниках. Подразумевается, что есть gnu make, в командной строке для студии 2012 выполняем команду 

gnumake tbb tbbmalloc target_ui=win8ui target_ui_mode=production

Со стороны библиотеки всё, переходим в студию.
Создаем новый проект "Blank App (XAML)" используя стандартный шаблон "Visual C++" ->"Windows Store". Для простоты оставим имя проекта, предложенное по умолчанию, "App1".
Теперь добавим каталог <каталог tbb>/include в свойство проекта "Additional Include Directories" и каталог с построенной библиотекой tbb.lib в "Additional Library Directories". 
Затем добавим пару кнопок на основную страницу (Класс App1.MainPage). После этого XAML файл страницы будет выглядеть примерно так

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Button Name="SR" Margin="167,262,0,406" Height="100" Width="300" 
         Content="Press to run Simple Reduction"></Button>
        <Button Name="DR" Margin="559,262,0,406" Height="100" Width="300" 
         Content="Press to run Deterministic Reduction"></Button>
    </Grid>
</Page>

Кстати, перед подключением библиотеки хорошо бы проверить, что до этого момента мы не успели накосячить в коде, и есть все необходимые права и лицензии разработчика. Для этого надо построить и запустить приложение, и проверить, что кнопки нажимаются, и ничего не падает. При положительном результате переходим к подключению библиотеки.

Подключаем TBB и добавляем обработчики нажатия кнопок. Для примера возьмем алгоритмы редукции (tbb::parallel_reduce) и детерминированной редукции(tbb::parallel_deterministic_reduce) и добавим в исходный файл для основной страницы MainPage.xaml.cpp: 

#include "tbb/tbb.h"

void App1::MainPage::SR_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    int N=1000000;
    float fr = 1.0f/(float)N;
    float sum = tbb::parallel_reduce(
        tbb::blocked_range<int>(0,N), 0.0f,
        [=](const tbb::blocked_range<int>& r, float sum)->float {
            for( int i=r.begin(); i!=r.end(); ++i )
                sum += fr;
            return sum;
    },
        []( float x, float y )->float {
            return x+y;
    }
    );	
    SR->Content="Press to run Simple Reduction\nThe result is " + sum.ToString();
}

void App1::MainPage::DR_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    int N=1000000;
    float fr = 1.0f/(float)N;
    float sum = tbb::parallel_deterministic_reduce(
        tbb::blocked_range<int>(0,N), 0.0f,
        [=](const tbb::blocked_range<int>& r, float sum)->float {
            for( int i=r.begin(); i!=r.end(); ++i )
                sum += fr;
            return sum;
    },
        []( float x, float y )->float {
            return x+y;
    }
    );	
    DR->Content="Press to run Deterministic Reduction\nThe result is " + sum.ToString();
}

И XAML файл для основной страницы будет выглядеть так

<Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Button Name="SR" Margin="167,262,0,406" Height="100" Width="300" 
         Content="Press to run Simple Reduction" Click="SR_Click"></Button>
        <Button Name="DR" Margin="559,262,0,406" Height="100" Width="300" 
         Content="Press to run Deterministic Reduction" Click="DR_Click"></Button>
    </Grid>
</Page>

Добавляем библиотеки tbb.dll и tbbmalloc.dll в контейнер приложения. Для этого нужно добавить файлы в проект (через project->add existing item) и выставить свойство "Content" в "Yes". В этом случае файлы будут скопированы в контейнер (AppX) внутри приложения и могут быть подгружены как при старте приложения, так и позже.
Приложение готово. Можно запустить симулятор и смотреть, как красиво нагружаются все логические процессоры при нажатии на кнопки:

Следующим шагом надо запустить "Windows App Cert Kit" и проверить, что приложение успешно проходит аттестацию:

Вот и всё! Простое приложение готово, теперь можно всё усложнять.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=31152