Kami mengkaji infrastruktur OpenMP menggunakan contoh pengkompil GCC. Gabungkan isihan dalam OpenMP. Sistem pengkomputeran. Ideologi OpenMP

Pengaturcaraan selari dengan OpenMP

Pengenalan................................................. ....... .............................................. ............. ..................................... ......

Pengaturcaraan selari................................................ ................ ................................. .................

Menulis program selari................................................. .......... ............................................ ...

Seni bina selari................................................ ... ................................................... ......... .........

OpenMP................................................. .. ................................................ ........ .............................................. .

Pengenalan kepada OpenMP.............................................. .... ................................................ .......... ......................

Model perisian OpenMP.............................................. .... ................................................ .......... .....

Bagaimanakah benang berinteraksi?................................................ .......... ....................................... ................. .....

Asas OpenMP................................................ ... ................................................... ......... ................................

Sintaks................................................. ................................................... ...... ....................................

Kawasan selari................................................ ... ................................................... ......... ...............

Model pelaksanaan................................................ ... ................................................... ......... ....................

Binaan OpenMP................................................ ... ................................................... ......... ......................

Syarat-syarat untuk dipenuhi................................................. .... ................................................ .......... ...................

Syarat peribadi, dikongsi, lalai............................................ ....... .............................................. ............. ...

Keadaan peribadi pertama................................................. ... ................................................... ......... ...............

Konstruk OpenMP untuk pengagihan kerja............................................ ..................... ..............................

Selari untuk/DO gelung................................................. ....... .............................................. ............. .....

Bahagian selari................................................ ... ................................................... ......... ..........

Reka bentuk tunggal................................................ ... ................................................... ......... ................

Syarat-syarat untuk dipenuhi (2)................................................ ....... .............................................. ............. ..............

Jika keadaan................................................. ... ................................................... ......... ................................

Keadaan peribadi terakhir................................................. ... ................................................... ......... ............

Keadaan pengurangan................................................. ... ................................................... ......... ...............

Syarat jadual................................................ ... ................................................... ......... ...................

Keadaan yang dipesan................................................ ... ................................................... ......... ....................

Pembolehubah persekitaran OpenMP................................................ ..... ................................................... ......

Fungsi perpustakaan OpenMP .............................................. .................... ................................ .......................... ..

Kebergantungan data................................................ ........ .............................................. .............. ..............

Alat penyegerakan dalam OpenMP.............................................. ...... ................................................ .......

Bahagian kritikal................................................ ... ................................................... ......... ...................

Bahagian atom................................................ ... ................................................... ......... ........................

Halangan................................................. ....... .............................................. ............. ..................................... .

Membetulkan perintah pelaksanaan................................................ ..................... ................................. ........................ .

Pembinaan siram................................................ ... ................................................... ......... ......................

Keupayaan OpenMP lanjutan................................................. .................... ................................ .................

Menyahpepijat kod OpenMP.............................................. ..... ................................................... ...........................

Menala prestasi kod OpenMP.............................................. ...... ................................

Pendekatan asas................................................ ... ................................................... ......... .......................

Penghuraian automatik................................................ ................... ................................. ............

Memprofilkan program................................................ .... ................................................ .......... ....

Hierarki ingatan .............................................. .... ................................................ .......... ........................

Tugasan................................................. ................................................... ...... ..............................................

Tugasan 1................................................ ... ................................................... ......... .......................................

Tugasan 2................................................ ... ................................................... ......... .......................................

Tugasan 3................................................ ... ................................................... ......... .......................................

Tugasan 4................................................ ... ................................................... ......... .......................................

Tugasan 5................................................ ... ................................................... ......... .......................................

Tugasan 6................................................ ... ................................................... ......... .......................................

pengenalan

Pengaturcaraan selari

Pengaturcaraan selari digunakan apabila program berjujukan perlu mengurangkan masa pelaksanaannya, atau apabila program berjujukan, disebabkan jumlah data yang banyak, tidak lagi sesuai dengan memori satu komputer. Arah pembangunan dalam bidang pengkomputeran berprestasi tinggi dengan tepat bertujuan untuk menyelesaikan dua masalah ini: mewujudkan sistem pengkomputeran yang berkuasa dengan besar memori capaian rawak di satu pihak, dan pembangunan perisian yang sesuai di pihak yang lain.

Pada asasnya, keseluruhan persoalannya adalah untuk meminimumkan nisbah harga/prestasi. Lagipun, anda sentiasa boleh membina (memasang) sistem komputer yang akan menyelesaikan masalah dengan berkesan, tetapi adakah harga penyelesaian sedemikian akan mencukupi? Dua arah pembangunan boleh dibezakan kelengkapan komputer: mesin vektor (Cray) dan kelompok ( komputer biasa, perisian standard).

Menulis program selari

Pembangunan program selari (PP) terdiri daripada tiga peringkat utama:

Penguraian tugas kepada subtugas. Sebaik-baiknya, subtugas ini harus berfungsi secara bebas antara satu sama lain (prinsip lokaliti data). Berkongsi data antara subtugas adalah operasi yang mahal, terutamanya jika ia ditukar melalui rangkaian.

Pengagihan tugas di kalangan pemproses (pemproses maya). Dalam sesetengah kes, isu ini boleh diserahkan kepada budi bicara persekitaran masa jalan perisian.

Menulis program menggunakan beberapa perpustakaan selari. Pilihan perpustakaan mungkin bergantung pada platform di mana program akan dilaksanakan, tahap prestasi yang diperlukan, dan sifat tugas itu sendiri.

Seni bina selari

Untuk sebahagian besar, semua sistem pengkomputeran dan komputer dibahagikan kepada tiga kumpulan:

Sistem Memori Teragih. Setiap pemproses mempunyai memori sendiri dan tidak boleh mengakses terus memori pemproses lain.

Membangunkan program seperti sistem, pengaturcara dalam secara eksplisit mesti menentukan keseluruhan sistem komunikasi (Message Passing). Perpustakaan: MPI, PVM, Shmem (Cray sahaja).

Sistem dengan memori biasa (berkongsi).. Pemproses boleh terus mengakses memori pemproses lain. Pemproses boleh duduk di bas yang sama (SMP). Memori yang dikongsi boleh diedarkan secara fizikal, tetapi kemudian kos untuk mengakses memori jauh boleh menjadi sangat tinggi dan pembangun perisian mesti mengambil kira perkara ini.

Pendekatan kepada pembangunan perisian: Benang, arahan pengkompil (OpenMP), mekanisme penghantaran mesej.

Sistem gabungan. Komputer pelbagai konfigurasi boleh digabungkan dalam kelompok.

  • Kang Soo Gatlin
  • Pete Isensi

Laksanakan multithreading tanpa usaha tambahan

Antara pakar yang terlibat dalam pengkomputeran selari, jenaka yang popular ialah "Pengkomputeran selari ialah teknologi masa hadapan...... dan ia akan sentiasa begitu." Jenaka ini tidak kehilangan relevannya selama beberapa dekad. Sentimen yang sama telah berleluasa dalam komuniti seni bina komputer, bimbang bahawa had kelajuan jam pemproses akan dicapai tidak lama lagi, tetapi frekuensi pemproses terus meningkat, walaupun pada kadar yang lebih perlahan daripada sebelumnya. Gabungan optimisme pakar pengkomputeran selari dan pesimisme arkitek sistem menyumbang kepada kemunculan revolusioner pemproses berbilang teras.

Pengeluar pemproses utama telah mengalihkan tumpuan mereka daripada meningkat frekuensi jam untuk melaksanakan keselarian dalam pemproses itu sendiri melalui penggunaan seni bina berbilang teras. Ideanya mudah: menyepadukan lebih daripada satu teras ke dalam satu pemproses. Sistem dengan pemproses dwi-teras pada asasnya adalah sama dengan komputer dwi-pemproses, dan sistem dengan pemproses empat-teras pada asasnya adalah sama dengan komputer empat-pemproses. Pendekatan ini mengelakkan banyak perkara masalah teknologi dikaitkan dengan peningkatan kelajuan jam, dan pada masa yang sama mencipta pemproses yang lebih cekap.

Itu semua baik dan bagus, tetapi melainkan apl anda menggunakan berbilang teras, ia tidak akan berprestasi secara berbeza. Di sinilah teknologi OpenMP berperanan, membantu pengaturcara C++ mencipta aplikasi berbilang benang dengan lebih pantas.

Tidak terfikir untuk menerangkan OpenMP secara terperinci dalam satu artikel, kerana ia adalah API yang sangat besar dan berkuasa. Pertimbangkan artikel ini sebagai pengenalan yang menunjukkan aplikasi pelbagai cara OpenMP untuk menulis pantas program berbilang benang. Jika kamu perlu Maklumat tambahan mengenai topik ini, kami mengesyorkan agar anda merujuk spesifikasi yang tersedia di tapak web OpenMP (www.openmp.org) - ia amat mudah dibaca.

Mendayakan OpenMP dalam Visual C++

Piawaian OpenMP telah dibangunkan pada tahun 1997 sebagai API yang bertujuan untuk menulis aplikasi mudah alih, berbilang benang. Pada mulanya ia berdasarkan bahasa Fortran, tetapi kemudiannya termasuk C/C++. Versi terkini OpenMP - 2.0; ia disokong sepenuhnya oleh Visual C++ 2005. Standard OpenMP juga disokong oleh platform Xbox 360.

Sebelum anda membuat kod, anda harus tahu cara mendayakan ciri OpenMP pengkompil. Untuk melakukan ini, gunakan pilihan pengkompil /openmp yang diperkenalkan dalam Visual C++ 2005. (Anda boleh mendayakan arahan OpenMP dalam halaman sifat projek dengan memilih Ciri Konfigurasi, C/C++, Bahasa dan menukar nilai sifat Sokongan OpenMP.) Apabila pilihan /openmp ditemui, pengkompil mentakrifkan simbol _OPENMP, yang boleh digunakan untuk menentukan sama ada kemudahan OpenMP didayakan. Untuk melakukan ini, tulis sahaja #ifndef _OPENMP.

OpenMP berkomunikasi dengan aplikasi melalui perpustakaan import vcomp.lib. Pustaka masa jalan yang sepadan dipanggil vcomp.dll. Versi nyahpepijat bagi perpustakaan import dan masa jalan (masing-masing vcompd.lib dan vcompd.dll) sokongan mesej tambahan tentang ralat yang dihasilkan oleh beberapa operasi haram. Harap maklum bahawa Visual C++ tidak menyokong pautan statik dengan perpustakaan OpenMP runtime, walaupun versi Xbox 360 menyokong ini.

Pemprosesan selari dalam OpenMP

Aplikasi OpenMP bermula dengan satu utas - yang utama. Aplikasi mungkin mengandungi kawasan selari, di mana utas utama mencipta kumpulan utas (termasuk utas utama). Pada penghujung rantau selari, kumpulan benang dihentikan dan pelaksanaan benang utama diteruskan. Rantau selari boleh bersarang dengan kawasan selari yang lain, di mana setiap benang rantau asal menjadi benang utama untuk kumpulan benangnya. Kawasan bersarang pula boleh merangkumi kawasan pada tahap bersarang yang lebih mendalam.

Pemprosesan selari dalam OpenMP digambarkan dalam Rajah. 1. Anak panah paling kiri mewakili utas utama, yang berjalan bersendirian sehingga mencapai kawasan selari pertama pada titik 1. Pada ketika ini, utas utama mencipta sekumpulan utas dan kini semuanya berjalan serentak di kawasan selari.

Pada titik 2, tiga daripada empat utas ini, setelah mencapai kawasan selari bersarang, mencipta kumpulan utas baharu. Tuan asal dan utas yang mencipta kumpulan baharu menjadi pemilik kumpulan mereka (tuan kumpulan tersebut). Ambil perhatian bahawa urutan mungkin membuat kumpulan baharu pada masa yang berbeza atau mungkin tidak menemui kawasan selari bersarang sama sekali.

Pada titik 3, kawasan selari bersarang berakhir. Setiap utas dalam kawasan selari bersarang menyegerakkan keadaannya dengan utas lain di rantau itu, tetapi kawasan berbeza tidak menyegerakkan antara satu sama lain. Pada titik 4 kawasan selari pertama berakhir, dan pada titik 5 kawasan baharu bermula. Data tempatan setiap utas dalam selang antara kawasan selari dikekalkan.

Ini adalah asas model pelaksanaan dalam OpenMP. Kini anda sudah bersedia untuk mengetahui tempat untuk mula membangunkan aplikasi selari.

Binaan OpenMP

OpenMP mudah digunakan dan hanya merangkumi dua jenis asas binaan: arahan pragma dan fungsi masa jalan OpenMP. Arahan Pragma biasanya memberitahu pengkompil untuk melaksanakan pelaksanaan selari blok kod. Semua arahan ini bermula dengan #pragma omp. Seperti mana-mana arahan pragma lain, ia diabaikan oleh pengkompil yang tidak menyokong teknologi tertentu - dalam dalam kes ini OpenMP.

Fungsi OpenMP digunakan terutamanya untuk menukar dan mendapatkan semula parameter persekitaran. Selain itu, OpenMP menyertakan fungsi API untuk menyokong beberapa jenis penyegerakan. Untuk menggunakan fungsi perpustakaan (masa jalan) OpenMP ini, anda mesti memasukkan fail pengepala omp.h dalam program anda. Jika anda hanya menggunakan arahan pragma OpenMP dalam aplikasi anda, anda tidak perlu memasukkan fail ini.

Untuk melaksanakan pelaksanaan selari blok aplikasi, anda hanya perlu menambah arahan pragma pada kod dan, jika perlu, gunakan fungsi masa jalan pustaka OpenMP. arahan pragma mempunyai format seterusnya:

#pragma omp<директива>[bahagian [[,] bahagian]...]

OpenMP menyokong selari, untuk, selari untuk, bahagian, bahagian, tunggal, induk, kritikal, siram, tersusun dan arahan atom, yang mentakrifkan sama ada mekanisme perkongsian kerja atau binaan penyegerakan. Dalam artikel ini kita akan membincangkan kebanyakan arahan.

Klausa ialah pengubah suai pilihan bagi arahan yang mempengaruhi tingkah lakunya. Senarai bahagian yang disokong oleh setiap arahan berbeza-beza, dan lima arahan (master, kritikal, flush, ordered, dan atomic) tidak menyokong bahagian sama sekali.

Pelaksanaan pemprosesan selari

Walaupun terdapat banyak arahan OpenMP, kami tidak memerlukan kesemuanya sekaligus. Arahan yang paling penting dan biasa adalah selari. Ia mencipta kawasan selari untuk blok berstruktur yang mengikutinya, sebagai contoh:

#pragma omp selari [bahagian[ [,] bahagian]...] blok berstruktur

Arahan ini memberitahu pengkompil bahawa blok berstruktur kod harus dilaksanakan secara selari, dalam berbilang benang. Setiap utas akan melaksanakan aliran arahan yang sama, tetapi bukan set arahan yang sama - semuanya bergantung pada pernyataan yang mengawal logik program, seperti if-else.

Sebagai contoh, pertimbangkan program klasik"Hai dunia":

#pragma omp selari ( printf("Hello World\n"); )

Pada sistem pemproses dwi anda sudah tentu mengharapkan untuk mendapatkan yang berikut:

Hello World Hello World

Walau bagaimanapun, hasilnya mungkin seperti ini:

NerakaNeraka oo WorWlodrl d

Pilihan kedua adalah mungkin kerana dua utas berjalan selari boleh cuba mencetak baris pada masa yang sama. Apabila dua atau lebih utas secara serentak cuba membaca atau mengubah suai sumber yang dikongsi (dalam kes kami, tetingkap konsol), keadaan perlumbaan berlaku. Ini adalah ralat bukan deterministik dalam kod program, yang amat sukar dicari. Pengaturcara bertanggungjawab untuk mencegah perlumbaan; Sebagai peraturan, ini dicapai dengan menggunakan kunci atau meminimumkan akses kepada sumber yang dikongsi.

Mari kita lihat contoh yang lebih serius yang menentukan purata dua elemen tatasusunan bersebelahan dan menulis keputusan kepada tatasusunan lain. Contoh ini menggunakan binaan OpenMP baharu kepada anda #pragma omp for, yang berkaitan dengan arahan perkongsian kerja. Arahan sedemikian digunakan bukan untuk pelaksanaan kod selari, tetapi untuk pengedaran logik sekumpulan benang untuk melaksanakan pembinaan logik kawalan yang ditentukan. Arahan #pragma omp untuk menyatakan bahawa apabila melaksanakan gelung for dalam kawasan selari, lelaran gelung harus diedarkan di antara utas kumpulan:

#pragma omp selari ( #pragma omp untuk for(int i = 1; i< size; ++i) x[i] = (y + y)/2; }

Jika kod ini dijalankan pada komputer empat pemproses dan saiz mempunyai nilai 100, lelaran 1-25 boleh diberikan kepada pemproses pertama, 26-50 kepada yang kedua, 51-75 kepada yang ketiga dan 76-99 kepada yang ketiga. yang keempat. Ini adalah tipikal untuk dasar penjadualan yang dipanggil statik. Kami akan membincangkan dasar penjadualan kemudian.

Perlu diingatkan bahawa penyegerakan halangan dilakukan pada penghujung kawasan selari. Dalam erti kata lain, apabila sampai ke penghujung rantau, semua utas disekat sehingga utas terakhir menyelesaikan kerjanya.

Jika #pragma omp untuk arahan dialih keluar daripada contoh yang diberikan, setiap urutan akan dilaksanakan kitaran penuh kerana, selepas melakukan banyak kerja tambahan:

#pragma omp selari ( for(int i = 1; i< size; ++i) x[i] = (y + y)/2; }

Oleh kerana gelung ialah binaan yang paling biasa di mana pelaksanaan kod boleh diselaraskan, OpenMP menyokong cara ringkas untuk menulis gabungan #pragma omp selari dan #pragma omp untuk arahan:

#pragma omp selari untuk for(int i = 1; i< size; ++i) x[i] = (y + y)/2;

Sila ambil perhatian bahawa gelung ini tidak mempunyai kebergantungan, iaitu, satu lelaran gelung tidak bergantung pada hasil lelaran lain. Tetapi dalam dua kitaran seterusnya terdapat dua jenis pergantungan:

Untuk(int i = 1; i<= n; ++i) // цикл 1 a[i] = a + b[i]; for(int i = 0; i < n; ++i) // цикл 2 x[i] = x + b[i];

Penyelarasan gelung 1 bermasalah kerana untuk melaksanakan lelaran i anda perlu mengetahui hasil lelaran i-1, iaitu lelaran i bergantung kepada lelaran i-1. Penyelarasan gelung 2 juga bermasalah, tetapi untuk sebab yang berbeza. Dalam gelung ini, anda boleh menilai nilai x[i] hingga x, namun, sebaik sahaja anda melakukan ini, anda tidak lagi dapat menilai nilai x. Kebergantungan lelaran i-1 pada lelaran i diperhatikan.

Apabila menyelaraskan gelung, anda mesti memastikan bahawa lelaran gelung tidak mempunyai kebergantungan. Jika gelung tidak mengandungi kebergantungan, pengkompil boleh melaksanakan gelung dalam sebarang susunan, walaupun secara selari. Pengkompil tidak menyemak sama ada keperluan penting ini dipenuhi - anda mesti menguruskannya sendiri. Jika anda memberitahu pengkompil untuk menyelaraskan gelung yang mengandungi kebergantungan, pengkompil akan mematuhi, mengakibatkan ralat.

Selain itu, OpenMP meletakkan sekatan pada gelung untuk yang boleh disertakan dalam #pragma omp untuk blok atau #pragma omp selari untuk blok. Untuk gelung mesti mengikut format berikut:

Untuk([jenis integer] i = gelung invarian; i (<,>,=,<=,>=) invarian gelung; i (+,-)= gelung invarian)

Keperluan ini diperkenalkan supaya OpenMP boleh menentukan bilangan lelaran apabila memasuki gelung.

Perbandingan sokongan benang dalam OpenMP dan Win32

Kami fikir adalah berguna untuk membandingkan contoh yang baru kami berikan, yang termasuk #pragma omp selari untuk arahan, dengan kod yang perlu kami tulis untuk menyelesaikan masalah yang sama menggunakan API Windows. Seperti yang anda lihat dalam Penyenaraian 1, ia memerlukan lebih banyak kod untuk mencapai hasil yang sama, dan di sebalik tabir, pilihan ini melakukan lebih banyak kerja. Oleh itu, pembina kelas ThreadData menentukan nilai permulaan dan hentian yang sepatutnya setiap kali benang dipanggil. OpenMP mengendalikan semua butiran ini sendiri dan menyediakan pengaturcara dengan cara tambahan untuk mengkonfigurasi kawasan dan kod selari.

Penyenaraian 1. Multithreading dalam Win32

Class ThreadData ( public: // Pembina memulakan medan mula dan berhenti ThreadData(int threadNum); int start; int stop; ); DWORD ThreadFn(void* passedInData) ( ThreadData *threadData = (ThreadData *)passedInData; for(int i = threadData->start; i< threadData->berhenti; ++i) x[i] = (y + y) / 2; pulangan 0; ) void ParallelFor() ( // Mulakan kumpulan benang untuk(int i=0; i< nTeams; ++i) ResumeThread(hTeams[i]); // Для каждого потока здесь неявно вызывается // метод ThreadFn // Ожидание завершения работы WaitForMultipleObjects(nTeams, hTeams, TRUE, INFINITE); } int main(int argc, char* argv) { // Создание групп потоков for(int i=0; i < nTeams; ++i) { ThreadData *threadData = new ThreadData(i); hTeams[i] = CreateThread(NULL, 0, ThreadFn, threadData, CREATE_SUSPENDED, NULL); } ParallelFor(); // имитация OpenMP-конструкции parallel for // Очистка for(int i=0; i < nTeams; ++i) CloseHandle(hTeams[i]); }

Data am dan peribadi

Membangunkan program selari, anda mesti memahami data mana yang dikongsi dan mana yang peribadi - bukan sahaja prestasi, tetapi juga kerja yang betul program. Dalam OpenMP perbezaan ini jelas, dan anda boleh mengkonfigurasinya secara manual.

Pembolehubah yang dikongsi boleh diakses oleh semua utas dalam kumpulan, jadi perubahan kepada pembolehubah sedemikian dalam satu utas boleh dilihat oleh utas lain dalam kawasan selari. Bagi pembolehubah persendirian, setiap utas dalam kumpulan mempunyai kejadian berasingan daripadanya, jadi perubahan kepada pembolehubah sedemikian dalam satu utas tidak menjejaskan kejadian mereka yang dimiliki oleh utas lain.

Secara lalai, semua pembolehubah dalam kawasan selari dikongsi, tetapi terdapat tiga pengecualian kepada peraturan ini. Pertama, indeks selari untuk gelung. Sebagai contoh, ini terpakai kepada pembolehubah i dalam kod yang ditunjukkan dalam Penyenaraian 2. Pembolehubah j bukan peribadi secara lalai, tetapi dibuat secara eksplisit melalui klausa firstprivate.

Penyenaraian 2. Bahagian arahan OpenMP dan bersarang untuk gelung

Jumlah apungan = 10.0f; MatrixClass myMatrix; int j = myMatrix.RowStart(); int i; #pragma omp selari ( #pragma omp untuk firstprivate(j) lastprivate(i) reduction(+: sum) for(i = 0; i< count; ++i) { int doubleI = 2 * i; for(; j < doubleI; ++j) { sum += myMatrix.GetElement(i, j); } } }

Kedua, pembolehubah tempatan bagi blok kawasan selari adalah peribadi. Dalam Rajah. 3 pembolehubah doubleI adalah sedemikian kerana ia diisytiharkan dalam rantau selari. Sebarang pembolehubah bukan statik dan bukan MatrixClass yang diisytiharkan dalam kaedah myMatrix::GetElement akan menjadi peribadi.

Ketiga, sebarang pembolehubah yang dinyatakan dalam bahagian persendirian, persendirian pertama, persendirian terakhir dan pengurangan akan menjadi persendirian. Dalam Penyenaraian 2, pembolehubah i, j dan jumlah dijadikan peribadi kepada setiap utas dalam kumpulan, bermakna setiap utas akan mempunyai salinannya sendiri bagi setiap pembolehubah ini.

Setiap daripada empat bahagian yang dinamakan menerima senarai pembolehubah, tetapi semantik bahagian ini berbeza. Bahagian peribadi mengatakan bahawa setiap urutan mesti membuat salinan peribadi setiap pembolehubah dalam senarai. Salinan peribadi akan dimulakan dengan nilai lalai (menggunakan pembina lalai jika sesuai). Sebagai contoh, jenis pembolehubah int mempunyai nilai lalai 0.

Klausa firstprivate mempunyai semantik yang sama, tetapi sebelum melaksanakan rantau selari, ia menentukan bahawa nilai pembolehubah persendirian disalin ke setiap utas, menggunakan pembina salinan jika sesuai.

Semantik bahagian lastprivate juga bertepatan dengan semantik bahagian peribadi, tetapi apabila lelaran terakhir bagi gelung atau bahagian binaan penyejajaran dilaksanakan, nilai pembolehubah yang dinyatakan dalam bahagian lastprivate diberikan kepada pembolehubah. daripada benang utama. Apabila sesuai, operator tugasan salinan digunakan untuk menyalin objek.

Bahagian pengurangan mempunyai semantik yang serupa, tetapi ia menerima pembolehubah dan pengendali. Pengendali yang disokong oleh bahagian ini disenaraikan dalam Jadual. 1, dan pembolehubah mesti mempunyai jenis skalar(cth. float, int atau long, tetapi bukan std::vector, int, dsb.). Pembolehubah bahagian pengurangan dimulakan dalam setiap utas dengan nilai yang dinyatakan dalam jadual. Pada penghujung blok kod, pernyataan klausa pengurangan digunakan pada setiap salinan peribadi pembolehubah serta nilai asal pembolehubah.

Jadual 1. Pengendali bahagian pengurangan

Dalam Penyenaraian 2, jumlah secara tersirat dimulakan pada setiap urutan kepada 0.0f (perhatikan bahawa jadual menunjukkan nilai kanonik 0, tetapi dalam kes ini ia mengambil bentuk 0.0f kerana jumlah ialah apungan). Selepas #pragma omp untuk blok dilaksanakan, operasi + dilakukan pada semua nilai separa dan nilai jumlah asal (yang dalam kes kami ialah 10.0f). Hasilnya diberikan kepada jumlah pembolehubah sepunya asal.

Pemprosesan selari dalam binaan selain gelung

Biasanya, OpenMP digunakan untuk menyelaraskan gelung, tetapi OpenMP juga menyokong paralelisme peringkat fungsi. Mekanisme ini dipanggil bahagian OpenMP. Ia agak mudah dan selalunya berguna.

Mari kita lihat salah satu algoritma yang paling penting dalam pengaturcaraan - quicksort. Sebagai contoh, kami melaksanakan kaedah rekursif untuk mengisih senarai integer dengan cepat. Demi kesederhanaan, kami memutuskan untuk tidak membuat versi templat universal kaedah, tetapi intipati perkara itu tidak berubah sama sekali. Kod untuk kaedah kami, yang dilaksanakan menggunakan bahagian OpenMP, ditunjukkan dalam Penyenaraian 3 (kod untuk kaedah Partition diabaikan untuk mengelakkan kekacauan keseluruhan gambar).

Penyenaraian 3. Isih pantas menggunakan sekatan selari

Void QuickSort (int numList, int nLower, int nUpper) ( if (nLower< nUpper) { // Разбиение интервала сортировки int nSplit = Partition (numList, nLower, nUpper); #pragma omp parallel sections { #pragma omp section QuickSort (numList, nLower, nSplit - 1); #pragma omp section QuickSort (numList, nSplit + 1, nUpper); } } }

DALAM dalam contoh ini Arahan #pragma pertama mencipta kawasan bahagian selari. Setiap bahagian ditakrifkan oleh arahan bahagian #pragma omp. Setiap bahagian dalam rantau selari diberikan satu utas daripada kumpulan utas, dan semua bahagian dilaksanakan serentak. Setiap bahagian memanggil kaedah QuickSort secara rekursif.

Seperti #pragma omp selari untuk konstruk, anda mesti memastikan bahagian itu bebas antara satu sama lain supaya ia boleh dilaksanakan secara selari. Jika bahagian berubah sumber yang dikongsi Tanpa menyegerakkan akses kepada mereka, hasilnya mungkin tidak dapat diramalkan.

Ambil perhatian bahawa contoh ini menggunakan trengkas #pragma omp bahagian selari, yang serupa dengan #pragma omp selari untuk konstruk. Dengan analogi dengan #pragma omp for, arahan bahagian #pragma omp boleh digunakan secara berasingan di kawasan selari.

Terdapat beberapa perkara lagi untuk dikatakan tentang kod yang ditunjukkan dalam Penyenaraian 3. Pertama, perhatikan bahawa bahagian selari dipanggil secara rekursif. Panggilan rekursif disokong oleh kedua-dua kawasan selari dan (seperti dalam contoh kami) bahagian selari. Jika penciptaan bahagian bersarang dibenarkan, selagi panggilan rekursif QuickSort akan mencipta lebih banyak urutan baharu. Ini mungkin bukan apa yang pengaturcara mahu, kerana pendekatan ini boleh membawa kepada penciptaan nombor besar aliran. Untuk mengehadkan bilangan utas, anda boleh melumpuhkan sarang dalam program anda. Aplikasi kami kemudiannya akan memanggil kaedah QuickSort secara rekursif menggunakan hanya dua utas.

Menyusun aplikasi ini tanpa pilihan /openmp akan menjana versi bersiri yang betul. Salah satu kelebihan OpenMP ialah ia serasi dengan penyusun yang tidak menyokong OpenMP.

Arahan Pragma untuk penyegerakan

Apabila berbilang benang berjalan serentak, selalunya terdapat keperluan untuk menyegerakkannya. OpenMP menyokong beberapa jenis penyegerakan yang membantu dalam banyak situasi.

Satu jenis ialah penyegerakan halangan tersirat, yang berlaku pada penghujung setiap kawasan selari untuk semua utas yang berkaitan dengannya. Mekanisme penyegerakan halangan adalah sedemikian rupa sehingga semua benang mencapai penghujung rantau selari, tiada benang boleh melintasi sempadannya.

Penyegerakan halangan tersirat juga dilakukan pada penghujung setiap blok bahagian #pragma omp untuk, #pragma omp tunggal dan #pragma omp. Untuk melumpuhkan penyegerakan halangan tersirat dalam mana-mana tiga blok perkongsian kerja ini, nyatakan bahagian nowait:

#pragma omp selari ( #pragma omp for nowwait for(int i = 1; i< size; ++i) x[i] = (y + y)/2; }

Seperti yang anda lihat, bahagian arahan penyejajaran ini mengatakan bahawa tidak perlu menyegerakkan benang pada penghujung gelung for, walaupun ia masih akan disegerakkan pada penghujung rantau selari.

Jenis kedua ialah penyegerakan halangan eksplisit. Dalam sesetengah situasi adalah dinasihatkan untuk melaksanakannya bersama-sama dengan yang tersirat. Untuk melakukan ini, masukkan arahan penghalang #pragma omp dalam kod anda.

Bahagian kritikal boleh digunakan sebagai penghalang. Dalam Win32 API, fungsi EnterCriticalSection dan LeaveCriticalSection digunakan untuk masuk dan keluar bahagian kritikal. Dalam OpenMP, arahan [nama] kritikal #pragma omp digunakan untuk ini. Ia mempunyai semantik yang sama seperti bahagian kritikal Win32 dan bergantung pada EnterCriticalSection. Anda boleh menggunakan bahagian kritikal bernama, dan kemudian akses kepada blok kod adalah saling eksklusif hanya kepada bahagian kritikal lain dengan nama yang sama (ini adalah benar untuk keseluruhan proses). Jika nama tidak dinyatakan, arahan itu dipadankan dengan beberapa nama yang dipilih oleh sistem. Akses kepada semua bahagian kritikal yang tidak dinamakan adalah saling eksklusif.

Di kawasan selari, selalunya terdapat blok kod yang anda mahu hanya satu utas untuk mempunyai akses, seperti blok kod yang bertanggungjawab untuk menulis data ke fail. Dalam kebanyakan situasi ini, tidak kira benang mana yang melaksanakan kod, cuma ia adalah satu-satunya utas. Untuk melakukan ini, OpenMP menggunakan arahan tunggal #pragma omp.

Kadang-kadang keupayaan arahan tunggal tidak mencukupi. Dalam sesetengah kes, anda mahu blok kod dilaksanakan oleh utas utama - contohnya, jika utas ini bertanggungjawab untuk memproses GUI dan anda memerlukannya untuk melaksanakan beberapa tugas. Kemudian arahan induk #pragma omp digunakan. Tidak seperti arahan tunggal, tiada halangan tersirat apabila memasuki atau meninggalkan blok induk.

Untuk melengkapkan semua operasi memori yang belum selesai sebelum memulakan operasi seterusnya, gunakan arahan #pragma omp flush, yang bersamaan dengan fungsi pengkompil dalaman _ReadWriteBarrier.

Ambil perhatian bahawa arahan pragma OpenMP mesti diproses oleh semua utas dalam kumpulan dalam susunan yang sama (atau tidak diproses oleh mana-mana utas sama sekali). Oleh itu, contoh kod berikut adalah tidak betul, dan keputusan pelaksanaannya tidak dapat diramalkan (pilihan yang berkemungkinan ialah ranap sistem atau pembekuan sistem):

#pragma omp selari ( if(omp_get_thread_num() > 3) ( #pragma omp single // kod tidak tersedia untuk semua thread x++; ) )

Rutin masa jalan OpenMP

Sebagai tambahan kepada arahan yang telah diterangkan, OpenMP menyokong beberapa rutin berguna. Ini termasuk dalam tiga kategori besar: masa jalan, penguncian/penyegerakan dan fungsi pemasa (yang terakhir tidak dibincangkan dalam artikel ini). Semua fungsi ini mempunyai nama bermula dengan omp_ dan ditakrifkan dalam fail pengepala omp.h.

Subrutin kategori pertama membolehkan anda membuat pertanyaan dan menetapkan pelbagai parameter Persekitaran operasi OpenMP. Fungsi yang namanya bermula dengan omp_set_ hanya boleh dipanggil di luar kawasan selari. Semua fungsi lain boleh digunakan di dalam kawasan selari dan di luarnya.

Untuk mengetahui atau menetapkan bilangan utas dalam kumpulan, gunakan fungsi omp_get_num_threads dan omp_set_num_threads. Yang pertama mengembalikan bilangan utas dalam kumpulan utas semasa. Jika utas panggilan tidak berjalan di rantau selari, fungsi ini mengembalikan 1. Kaedah omp_set_num_thread menetapkan bilangan utas untuk dijalankan di rantau selari seterusnya yang ditemui benang yang sedang berjalan. Di samping itu, bilangan utas yang digunakan untuk melaksanakan kawasan selari bergantung pada dua parameter lain persekitaran OpenMP: sokongan untuk penciptaan benang dinamik dan sarang rantau.

Sokongan untuk penciptaan benang dinamik ditentukan oleh nilai sifat boolean, yang lalai kepada palsu. Jika, apabila aliran memasuki kawasan selari, sifat ini mempunyai nilai palsu, masa jalan OpenMP mencipta kumpulan yang bilangan utasnya sama dengan nilai yang dikembalikan oleh fungsi omp_get_max_threads. Secara lalai, omp_get_max_threads mengembalikan bilangan utas yang disokong oleh perkakasan atau nilai pembolehubah OMP_NUM_THREADS. Jika sokongan untuk penciptaan benang dinamik didayakan, masa jalan OpenMP akan mencipta kumpulan yang boleh mengandungi nombor berubah-ubah benang, tidak melebihi nilai yang dikembalikan oleh fungsi omp_get_max_threads.

Sarang bagi kawasan selari juga ditentukan oleh sifat boolean, yang ditetapkan kepada palsu secara lalai. Sarang rantau selari berlaku apabila benang yang sudah melaksanakan rantau selari menemui kawasan selari yang lain. Jika lampiran dibenarkan, a kumpulan baru aliran, sambil mematuhi peraturan yang diterangkan sebelum ini. Dan jika bersarang tidak dibenarkan, kumpulan dibentuk yang mengandungi satu benang.

Untuk menetapkan dan membaca sifat yang menentukan kemungkinan mencipta benang secara dinamik dan kawasan selari bersarang, gunakan fungsi omp_set_dynamic, omp_get_dynamic, omp_set_nested dan omp_get_nested. Di samping itu, setiap rangkaian boleh meminta maklumat tentang persekitarannya. Untuk mengetahui nombor utas dalam kumpulan utas, hubungi omp_get_thread_num. Ingat bahawa ia tidak mengembalikan ID utas Windows, tetapi nombor dalam julat dari 0 hingga omp_get_num_threads - 1.

Fungsi omp_in_parallel membolehkan benang mengetahui sama ada ia sedang melaksanakan rantau selari dan omp_get_num_procs mengembalikan bilangan pemproses dalam mesin.

Untuk lebih memahami perhubungan pelbagai fungsi masa jalan, lihat Penyenaraian 4. Dalam contoh ini, kami melaksanakan empat kawasan selari yang berasingan dan dua kawasan bersarang.

Penyenaraian 4. Menggunakan rutin masa jalan OpenMP

#termasuk #termasuk int main() ( omp_set_dynamic(1); omp_set_num_threads(10); #pragma omp parallel // kawasan selari 1 ( #pragma omp single printf("Jumlah benang dalam kawasan dinamik ialah = %d\n", omp_get_num_threads()); ) printf("\n"); omp_set_dynamic(0); omp_set_num_threads(10); #pragma omp parallel // kawasan selari 2 ( #pragma omp single printf("Jumlah benang dalam kawasan bukan dinamik ialah = %d\n" , omp_get_num_threads()); ) printf("\n"); omp_set_dynamic(1); omp_set_num_threads(10); #pragma omp parallel // kawasan selari 3 ( #pragma omp parallel ( #pragma omp single printf("Num threads in rantau orang kurang upaya bersarang ialah = %d\n", omp_get_num_threads()); ) ) printf("\n"); omp_set_nested(1); #pragma omp parallel // kawasan selari 4 ( #pragma omp parallel ( #pragma omp single printf("Jumlah benang dalam kawasan bersarang ialah = %d\n", omp_get_num_threads()); ) ) )

Menyusun kod ini dalam Visual Studio 2005 dan menjalankannya pada komputer dwi-pemproses biasa, kami mendapat hasil berikut:

Bilangan benang dalam kawasan dinamik ialah = 2 Bilangan benang dalam kawasan bukan dinamik ialah = 10 Bilangan benang dalam kawasan yang dilumpuhkan bersarang ialah = 1 Bilangan benang dalam kawasan yang dilumpuhkan bersarang ialah = 1 Bilangan benang dalam kawasan bersarang ialah = 2 Bilangan benang dalam kawasan bersarang ialah = 2

Untuk wilayah pertama yang kami sertakan penciptaan dinamik benang dan tetapkan bilangan utas kepada 10. Keputusan program menunjukkan bahawa dengan penciptaan benang dinamik didayakan, persekitaran masa jalan OpenMP memutuskan untuk mencipta kumpulan yang mengandungi hanya dua utas, memandangkan komputer mempunyai dua pemproses. Untuk rantau selari kedua, masa jalan OpenMP mencipta kumpulan benang 10 kerana penciptaan benang dinamik telah dilumpuhkan untuk rantau itu.

Keputusan menjalankan kawasan selari ketiga dan keempat menggambarkan akibat mendayakan dan melumpuhkan keupayaan untuk menyarang kawasan. Di kawasan selari ketiga, sarang telah dilumpuhkan, jadi tiada benang baharu dicipta untuk kawasan selari bersarang - kedua-dua kawasan selari luar dan bersarang telah dilaksanakan oleh dua utas. Di kawasan selari keempat yang bersarang didayakan, sekumpulan dua utas telah dibuat untuk kawasan selari bersarang (iaitu, sejumlah empat utas sedang melaksanakan rantau itu). Proses menggandakan bilangan benang untuk setiap kawasan selari bersarang boleh diteruskan sehingga anda kehabisan ruang tindanan. Dalam praktiknya, adalah mungkin untuk membuat beberapa ratus utas, walaupun kos yang berkaitan dengan ini akan dengan mudah mengatasi sebarang faedah.

Seperti yang anda mungkin perasan, penciptaan benang dinamik telah didayakan untuk kawasan selari ketiga dan keempat. Mari lihat apa yang berlaku jika kita menjalankan kod yang sama, melumpuhkan penciptaan benang dinamik:

Omp_set_dynamic(0); omp_set_nested(1); omp_set_num_threads(10); #pragma omp parallel ( #pragma omp parallel ( #pragma omp single printf("Jumlah benang dalam kawasan bersarang ialah = %d\n", omp_get_num_threads()); ) )

Dan apa yang berlaku adalah apa yang anda jangkakan. Sekumpulan 10 utas dibuat untuk kawasan selari pertama, kemudian apabila memasuki kawasan selari bersarang, kumpulan 10 utas juga dibuat untuk setiap satu daripada 10 utas ini. Sebanyak 100 utas melaksanakan kawasan selari bersarang:

Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Bilangan benang dalam kawasan bersarang ialah = 10 Num thread dalam kawasan bersarang ialah = 10 Num thread dalam kawasan bersarang ialah = 10 Num thread dalam kawasan bersarang ialah = 10

Kaedah penyegerakan/mengunci

OpenMP juga termasuk fungsi yang direka untuk penyegerakan kod. Terdapat dua jenis kunci dalam OpenMP: mudah dan bersarang (nestable); Kedua-dua jenis kunci boleh berada dalam salah satu daripada tiga keadaan - tidak dimulakan, dikunci dan tidak dikunci.

Kunci mudah (omp_lock_t) tidak boleh diperoleh lebih daripada sekali, walaupun dengan urutan yang sama. Kunci bersarang (omp_nest_lock_t) adalah sama dengan kunci mudah, kecuali apabila benang cuba memperoleh kunci bersarang yang sudah dimilikinya, kunci itu tidak disekat. Selain itu, OpenMP menyimpan rekod rujukan kunci bersarang dan menjejaki berapa kali ia telah ditetapkan.

OpenMP menyediakan rutin yang melaksanakan operasi pada kunci ini. Setiap fungsi sedemikian mempunyai dua pilihan: untuk kunci mudah dan untuk kunci bersarang. Anda boleh melakukan lima tindakan pada kunci: memulakannya, memperolehnya (memperolehnya), melepaskannya, menyemaknya dan memusnahkannya. Semua operasi ini sangat serupa dengan fungsi Win32 untuk bekerja dengan bahagian kritikal, dan ini bukan kemalangan: sebenarnya, teknologi OpenMP dilaksanakan sebagai pembalut di sekeliling fungsi ini. Surat-menyurat antara fungsi OpenMP dan Win32 digambarkan dalam Jadual. 2.

Jadual 2. Fungsi untuk bekerja dengan kunci dalam OpenMP dan Win32

Penyekatan OpenMP mudah Penguncian OpenMP bersarang Fungsi Win32
omp_lock_t omp_nest_lock_t CRITICAL_SECTION
omp_init_lock omp_init_nest_lock InitializeCriticalSection
omp_destroy_lock omp_destroy_nest_lock DeleteCriticalSection
omp_set_lock omp_set_nest_lock EnterCriticalSection
omp_unset_lock omp_unset_nest_lock TinggalkanBahagian Kritikal
omp_test_lock omp_test_nest_lock CubaEnterCriticalSection

Anda boleh menggunakan kedua-dua rutin masa jalan dan arahan penyegerakan untuk menyegerakkan kod. Kelebihan arahan ialah ia berstruktur dengan baik. Ini menjadikannya lebih jelas dan memudahkan anda mencari tempat anda masuk dan keluar dari kawasan yang disegerakkan.

Kelebihan rutin masa jalan ialah fleksibiliti. Sebagai contoh, anda boleh menghantar kunci ke fungsi lain dan menetapkan/melepaskannya dalam fungsi itu. Ini tidak boleh dilakukan apabila menggunakan arahan. Secara umum, melainkan anda memerlukan fleksibiliti yang disediakan oleh rutin masa jalan sahaja, adalah lebih baik untuk menggunakan arahan penyegerakan.

Pemprosesan selari struktur data

Penyenaraian 5 menunjukkan kod untuk dua gelung berjalan selari, pada permulaannya masa jalan tidak mengetahui bilangan lelaran. Contoh pertama berulang pada elemen bekas std::vector STL, dan yang kedua berulang pada elemen senarai terpaut standard.

Penyenaraian 5. Melakukan bilangan lelaran yang tidak diketahui

#pragma omp parallel ( // Pemprosesan selari vektor STL std::vector ::iterator iter; for(iter = xVect.begin(); iter != xVect.end(); ++iter) ( #pragma omp single nowait ( process1(*iter); ) ) // Pemprosesan selari senarai terpaut standard untuk(LList *listWalk = listHead; listWalk != NULL; listWalk = listWalk->next) ( #pragma omp single nowait ( process2(listWalk); ) ) )

Dalam contoh vektor STL, setiap utas dalam kumpulan utas melaksanakan gelung for dan mempunyai contoh lelarannya sendiri, tetapi pada setiap lelaran, hanya satu utas memasuki blok tunggal (ini ialah semantik arahan tunggal). Semua tindakan yang menjamin pelaksanaan tunggal blok tunggal pada setiap lelaran diambil alih oleh persekitaran masa jalan OpenMP. Terdapat overhed yang ketara untuk melaksanakan gelung dengan cara ini, jadi ia hanya berguna jika terdapat banyak kerja yang dilakukan dalam fungsi process1. Dalam contoh dengan senarai terpaut logik yang sama dilaksanakan.

Perlu diingat bahawa dalam contoh dengan vektor STL, sebelum memasuki gelung, kita boleh menentukan bilangan lelarannya dengan nilai std::vector.size, yang membolehkan kita membawa gelung ke bentuk kanonik untuk OpenMP:

#pragma omp selari untuk for(int i = 0; i< xVect.size(); ++i) process(xVect[i]);

Ini dengan ketara mengurangkan overhed masa jalan dan merupakan pendekatan yang kami cadangkan untuk memproses tatasusunan, vektor dan mana-mana bekas lain yang elemennya boleh diulang dalam gelung for yang mengikut bentuk kanonik untuk OpenMP.

Algoritma penjadualan yang lebih kompleks

Secara lalai, OpenMP menggunakan algoritma yang dipanggil penjadualan statik untuk menjadualkan pelaksanaan selari bagi gelung. Ini bermakna semua urutan dalam kumpulan dilaksanakan nombor yang sama lelaran gelung. Jika n ialah bilangan lelaran gelung, dan T ialah bilangan utas dalam kumpulan, setiap utas akan melakukan lelaran n/T (jika n tidak boleh dibahagikan dengan T, bukan masalah besar). Walau bagaimanapun, OpenMP turut menyokong mekanisme penjadualan lain yang optimum dalam situasi berbeza: penjadualan dinamik, penjadualan masa jalan dan penjadualan berpandu.

Untuk menentukan salah satu mekanisme penjadualan ini, gunakan bahagian jadual #pragma omp untuk atau #pragma omp selari untuk arahan. Format bahagian ini kelihatan seperti ini:

Jadual(algoritma penjadualan[, bilangan lelaran])

Berikut ialah contoh arahan ini:

#pragma omp selari untuk jadual(dinamik, 15) untuk(int i = 0; i< 100; ++i) ... #pragma omp parallel #pragma omp for schedule(guided)

Dalam penjadualan dinamik, setiap utas melaksanakan bilangan lelaran tertentu. Jika nombor ini tidak dinyatakan, ia lalai kepada 1. Selepas utas melengkapkan lelaran yang ditentukan, ia beralih ke set lelaran seterusnya. Ini berterusan sehingga semua lelaran selesai. Set lelaran terakhir mungkin lebih kecil daripada set asal.

Dalam penjadualan terurus, bilangan lelaran yang dilakukan oleh setiap urutan ditentukan oleh formula berikut:

Number_of_iterations_executed by a thread = max(number_of_unallocated_iterations/omp_get_num_threads(), bilangan lelaran)

Setelah melengkapkan lelaran yang ditetapkan, benang meminta satu lagi set lelaran, yang bilangannya ditentukan oleh formula yang diberikan. Oleh itu, bilangan lelaran yang diberikan kepada setiap utas berkurangan dari semasa ke semasa. Set lelaran terakhir mungkin kurang daripada nilai yang dikira oleh formula.

Dengan menyatakan arahan #pragma omp untuk jadual(dinamik, 15), gelung untuk 100 lelaran boleh dilaksanakan oleh empat utas seperti berikut:

Thread 0 dibenarkan untuk melaksanakan lelaran 1-15 Thread 1 dibenarkan untuk melaksanakan lelaran 16-30 Thread 2 dibenarkan untuk melaksanakan lelaran 31-45 Thread 3 dibenarkan untuk melaksanakan lelaran 46-60 Thread 2 melengkapkan lelaran Thread 2 dibenarkan untuk melaksanakan daripada lelaran 61-75 Thread 3 melengkapkan pelaksanaan lelaran Thread 3 menjadi dibenarkan untuk melaksanakan lelaran 76-90 Thread 0 melengkapkan pelaksanaan lelaran Thread 0 menjadi dibenarkan untuk melaksanakan lelaran 91-100

Tetapi inilah hasil daripada melaksanakan gelung yang sama dengan empat utas mungkin jika arahan #pragma omp untuk jadual(berpandu, 15) ditentukan:

Thread 0 dibenarkan untuk melaksanakan lelaran 1-25 Thread 1 dibenarkan untuk melaksanakan lelaran 26-44 Thread 2 dibenarkan untuk melaksanakan lelaran 45-59 Thread 3 dibenarkan untuk melaksanakan lelaran 60-64 Thread 2 melengkapkan lelaran Thread 2 dibenarkan untuk melaksanakan daripada lelaran 65-79 Thread 3 melengkapkan pelaksanaan lelaran Thread 3 menjadi dibenarkan untuk melaksanakan lelaran 80-94 Thread 2 melengkapkan pelaksanaan lelaran Thread 2 menjadi dibenarkan untuk melaksanakan lelaran 95-100

Penjadualan dinamik dan terkawal ialah pilihan yang baik jika jumlah kerja yang berbeza dilakukan pada setiap lelaran, atau jika sesetengah pemproses lebih cekap daripada yang lain. Dengan penjadualan statik, tiada cara untuk mengimbangi beban pada benang yang berbeza. Dengan penjadualan dinamik dan terurus, beban diagihkan secara automatik - inilah intipati pendekatan ini. Penjadualan terurus biasanya menjalankan kod lebih cepat daripada penjadualan dinamik disebabkan overhed penjadualan yang lebih rendah.

Pendekatan terakhir - penjadualan masa larian - bukanlah algoritma penjadualan, tetapi satu cara untuk memilih salah satu daripada tiga algoritma yang diterangkan secara dinamik. Jika parameter masa jalan ditentukan dalam bahagian jadual, masa jalan OpenMP menggunakan algoritma penjadualan yang ditentukan untuk gelung khusus menggunakan pembolehubah OMP_SCHEDULE. Ia mempunyai format "jenis [, bilangan lelaran]", contohnya:

Tetapkan OMP_SCHEDULE=dinamik,8

Penjadualan masa jalan menyediakan sedikit kelonggaran dalam memilih jenis penjadualan, dengan penjadualan statik menjadi lalai.

Bila hendak menggunakan OpenMP?

Mengetahui masa untuk menggunakan teknologi OpenMP adalah sama pentingnya dengan mengetahui cara menggunakannya. Kami berharap nasihat kami akan membantu anda.

Platform sasaran ialah multiprocessor atau multicore. Jika aplikasi menggunakan sepenuhnya sumber satu teras atau pemproses, maka menjadikannya berbilang benang menggunakan OpenMP hampir pasti akan meningkatkan prestasinya.

Aplikasi mestilah merentas platform. OpenMP ialah API merentas platform dan disokong secara meluas. Dan kerana ia dilaksanakan berdasarkan arahan pragma, aplikasi boleh disusun walaupun menggunakan pengkompil yang tidak menyokong standard OpenMP.

Pelaksanaan gelung perlu disejajarkan. OpenMP menunjukkan potensi penuhnya apabila mengatur pelaksanaan gelung selari. Jika aplikasi anda mempunyai gelung panjang tanpa kebergantungan, OpenMP ialah penyelesaian yang ideal.

Sebelum anda mengeluarkan apl anda, anda perlu meningkatkan prestasinya. Oleh kerana OpenMP tidak memerlukan sebarang reka bentuk semula seni bina aplikasi anda, ia bagus untuk membuat perubahan kecil pada kod anda untuk meningkatkan prestasi.

Pada masa yang sama, ia harus diakui bahawa OpenMP bukanlah ubat penawar untuk semua penyakit. Teknologi ini ditujukan terutamanya kepada pembangun berprestasi tinggi sistem pengkomputeran dan paling berkesan jika kod tersebut termasuk banyak gelung dan berfungsi dengan tatasusunan data yang dikongsi.

Mencipta kedua-dua benang biasa dan kawasan OpenMP selari memerlukan kos. Agar OpenMP memberi manfaat, faedah kelajuan yang disediakan oleh rantau selari mesti melebihi kos mencipta kumpulan benang. Dalam OpenMP versi Visual C++, kumpulan benang dibuat apabila memasuki kawasan selari pertama. Setelah rantau selesai, kumpulan benang digantung sehingga diperlukan lagi. Di sebalik tabir, OpenMP menggunakan kumpulan benang Windows. nasi. Rajah 2 menggambarkan peningkatan prestasi program ringkas yang diberikan pada permulaan artikel, yang dicapai berkat OpenMP pada komputer dwi-pemproses dengan pelbagai nombor lelaran. Peningkatan prestasi maksimum adalah kira-kira 1.7 daripada yang asal, yang biasa untuk sistem dwi-pemproses.

hidup carta ini Paksi-y mewakili nisbah masa pelaksanaan berurutan kod kepada masa pelaksanaan selari kod yang sama. Ambil perhatian bahawa versi selari mengatasi versi berjujukan dalam kira-kira 5000 lelaran, tetapi ini hampir senario terburuk. Kebanyakan gelung selari akan dilaksanakan lebih cepat daripada gelung berjujukan walaupun dengan lelaran yang jauh lebih sedikit. Ini bergantung pada jumlah kerja yang dilakukan dalam setiap lelaran. Walau apa pun, graf ini menunjukkan betapa pentingnya menilai prestasi perisian. Menggunakan OpenMP sahaja tidak menjamin bahawa kod anda akan berfungsi dengan lebih pantas.

Arahan pragma OpenMP mudah digunakan, tetapi tidak memberikan maklumat ralat terperinci. Jika anda menulis aplikasi kritikal misi yang perlu mengesan ralat dan pulih dengan betul kerja biasa, OpenMP mungkin harus ditinggalkan (mengikut sekurang-kurangnya, Selamat tinggal). Sebagai contoh, jika OpenMP tidak boleh mencipta benang untuk kawasan selari atau bahagian kritikal, tingkah laku program menjadi tidak ditentukan. Dalam Visual C++ 2005, masa jalan OpenMP terus cuba untuk dilaksanakan tugas yang dikehendaki, selepas itu ia berputus asa. Dalam versi OpenMP akan datang, antara lain, kami akan melaksanakan mekanisme pemberitahuan ralat standard.

Satu lagi situasi di mana anda perlu berwaspada ialah apabila menggunakan benang Windows dengan benang OpenMP. Benang OpenMP adalah berdasarkan pada benang Windows, jadi ia berjalan dengan sempurna dalam proses yang sama. Malangnya, OpenMP tidak tahu apa-apa tentang utas Windows yang dibuat oleh modul lain. Ini menimbulkan dua masalah: pertama, masa jalan OpenMP tidak menjejaki utas Windows yang lain, dan kedua, kaedah penyegerakan OpenMP tidak menyegerakkan utas Windows kerana ia bukan sebahagian daripada kumpulan utas.

Perangkap yang boleh anda alami apabila menggunakan OpenMP

Walaupun menggunakan OpenMP tidak sukar sama sekali, beberapa aspek masih memerlukan perhatian khusus. Sebagai contoh, pembolehubah indeks selari paling luar untuk gelung adalah peribadi, tetapi pembolehubah indeks bagi gelung bersarang adalah awam secara lalai. Apabila bekerja dengan gelung bersarang, anda biasanya mahu indeks gelung dalam menjadi peribadi. Gunakan bahagian peribadi untuk ini.

Apabila membangunkan aplikasi OpenMP, anda harus berhati-hati apabila membuang pengecualian C++. Jika aplikasi melemparkan pengecualian dalam kawasan selari, ia mesti dikendalikan di rantau yang sama dengan urutan yang sama. Dengan kata lain, pengecualian tidak boleh meninggalkan rantau ini. Sebagai peraturan umum, sebarang pengecualian yang mungkin dilemparkan dalam kawasan selari harus ditangkap. Jika anda tidak menangkap pengecualian di rantau serentak yang sama, aplikasi mungkin akan ranap.

Untuk dapat membuka blok berstruktur, ungkapan

#pragma omp<директива>[bab]

mesti diakhiri dengan simbol baris baru, tetapi tidak pendakap kerinting. Arahan yang berakhir dengan pendakap kerinting akan mengakibatkan ralat penyusunan1:

// Bad #pragma omp parallel ( // Ralat kompilasi) // Good #pragma omp parallel ( // Kod)

Menyahpepijat aplikasi OpenMP dalam Visual Studio 2005 boleh menjadi sukar. Khususnya, kesulitan tertentu dikaitkan dengan memasuki dan/atau keluar dari kawasan selari dengan menekan kekunci F10/F11. Ini kerana pengkompil menjana kod tambahan untuk memanggil masa jalan dan kumpulan benang. Penyahpepijat tidak tahu tentang perkara ini, jadi perkara yang anda lihat mungkin kelihatan pelik kepada anda. Kami mengesyorkan menetapkan titik putus dalam kawasan selari dan menekan F5 untuk memukulnya. Untuk keluar dari kawasan selari, tetapkan titik putus di luar kawasan itu dan tekan F5.

Apabila berada di dalam kawasan selari, Tetingkap Benang penyahpepijat akan memaparkan maklumat tentang benang yang berjalan dalam kumpulan benang. ID urutan ini tidak akan sepadan dengan utas OpenMP, tetapi dengan utas Windows yang mendasari.

Pada masa ini, anda tidak boleh menggunakan Pengoptimuman Berpandu Profil (PGO) dengan OpenMP. Nasib baik, teknologi OpenMP adalah berdasarkan arahan pragma, jadi anda boleh menyusun aplikasi anda dengan pilihan /openmp dan dengan PGO dan melihat pendekatan mana yang lebih cekap.

OpenMP dan .NET

Beberapa orang mengaitkan pengkomputeran berprestasi tinggi dengan .NET, tetapi Visual C++ 2005 memperbaiki keadaan ini. Nota khusus ialah kami telah membuat OpenMP berfungsi bersama-sama dengan kod C++ terurus. Untuk mencapai matlamat ini, kami telah menjadikan /openmp serasi dengan /clr dan /clr:OldSyntax. Iaitu, anda boleh menggunakan OpenMP untuk melaksanakan kaedah jenis .NET secara selari yang tertakluk kepada kutipan sampah. Sila ambil perhatian bahawa /openmp pada masa ini tidak serasi dengan sama ada /clr:safe atau /clr:pure, tetapi kami merancang untuk membetulkannya.

Kita harus menyebut satu had penting yang dikaitkan dengan menggunakan OpenMP dalam kod terurus. Aplikasi yang menggunakan OpenMP hanya boleh digunakan dalam satu domain aplikasi. Apabila memuatkan AppDomain lain ke dalam proses yang telah memuatkan masa jalan OpenMP, aplikasi mungkin ranap.

OpenMP ialah teknologi selari aplikasi yang mudah tetapi berkuasa. Ia membolehkan anda melaksanakan pelaksanaan selari kedua-dua gelung dan blok kod berfungsi. Ia boleh disepadukan dengan mudah ke dalam aplikasi sedia ada dan boleh didayakan/dilumpuhkan dengan satu pilihan pengkompil. OpenMP membolehkan anda menggunakan sepenuhnya kuasa pengkomputeran pemproses berbilang teras. Kami amat menasihati anda untuk membiasakan diri dengan spesifikasi OpenMP. Semoga berjaya dalam membangunkan program berbilang benang!

Infrastruktur OpenMP membolehkan anda melaksanakan teknologi pengaturcaraan selari dengan berkesan dalam C, C++ dan Fortran. GNU Compiler Collection (GCC) versi 4.2 menyokong spesifikasi OpenMP 2.5 dan GCC versi 4.4 menyokong spesifikasi OpenMP 3 yang terkini. Penyusun lain, termasuk Microsoft® Visual Studio, juga menyokong OpenMP. Artikel ini akan mengajar anda cara menggunakan pragmas Pengkompil OpenMP; ia juga mengandungi maklumat tentang beberapa API OpenMP dan merangkumi beberapa teknik pengkomputeran selari menggunakan OpenMP. Semua contoh dalam artikel ini menggunakan pengkompil GCC 4.2.

Permulaan kerja

Kelebihan besar OpenMP ialah tidak ada keperluan untuk tindakan tambahan, kecuali pemasangan standard pengkompil GCC. Aplikasi OpenMP mesti disusun dengan pilihan -fopenmp.

Mencipta aplikasi OpenMP pertama

Mari kita mulakan dengan menulis aplikasi mudah Hai dunia! mengandungi pragma tambahan. Kod untuk aplikasi ini ditunjukkan dalam Penyenaraian 1.

Penyenaraian 1. Program "Hello World" yang ditulis menggunakan OpenMP
#termasuk int main() ( #pragma omp parallel ( std::cout<< "Hello World!\n"; } }

Selepas menyusun dan menjalankan kod ini menggunakan g++, anda akan melihat mesej berikut pada skrin anda: Hai dunia!. Sekarang mari kita susun semula kod dengan pilihan -fopenmp. Keputusan program dibentangkan dalam Penyenaraian 2.

Penyenaraian 2. Menyusun dan menjalankan kod menggunakan pilihan -fopenmp
tintin$ g++ test1.cpp -fopenmp tintin$ ./a.out Hello World! Hai dunia! Hai dunia! Hai dunia! Hai dunia! Hai dunia! Hai dunia! Hai dunia!

Apa yang berlaku? Apabila anda menggunakan pilihan pengkompil -fopenmp, arahan selari #pragma omp akan dimainkan. Semasa penyusunan, dalaman GCC mencipta seberapa banyak benang selari yang boleh dilaksanakan di bawah keadaan beban sistem yang optimum (bergantung pada konfigurasi perkakasan dan sistem pengendalian), dengan setiap utas yang dibuat melaksanakan kod yang disertakan dalam blok selepas pragma. Tingkah laku ini dipanggil keselarian tersirat, dan teras OpenMP terdiri daripada satu set pragma yang berkuasa yang menyelamatkan anda daripada menulis banyak serpihan kod biasa (untuk keseronokan, anda boleh membandingkan kod yang diberikan dengan pelaksanaan tugas yang sama menggunakan benang POSIX). Saya menggunakan komputer dengan pemproses Intel® Core i7 dengan 4 teras fizikal 2 teras logik setiap satu, yang menerangkan keputusan dalam Penyenaraian 2 (8 utas = 8 teras logik).

Ciri selari OpenMP

Bilangan utas boleh dikawal dengan mudah menggunakan pragma dengan argumen num_threads. Di bawah ialah kod daripada Penyenaraian 1 dengan bilangan utas yang ditetapkan (5 utas):

Penyenaraian 3. Mengawal bilangan utas menggunakan num_threads
#termasuk int main() ( #pragma omp selari num_threads(5) ( std::cout<< "Hello World!\n"; } }

Daripada argumen num_threads, anda boleh menggunakan kaedah alternatif untuk menentukan bilangan utas pelaksanaan kod. Di sini kita sampai ke API OpenMP pertama yang dipanggil omp_set_num_threads. Fungsi ini ditakrifkan dalam fail pengepala omp.h. Anda tidak perlu menggunakan mana-mana perpustakaan tambahan untuk menjalankan kod dalam Penyenaraian 4; hanya gunakan pilihan -fopenmp.

Penyenaraian 4. Kawalan benang berbutir halus dengan omp_set_num_threads
#termasuk #termasuk int main() ( omp_set_num_threads(5); #pragma omp parallel ( std::cout<< "Hello World!\n"; } }

Akhir sekali, pembolehubah persekitaran luaran boleh digunakan untuk mengawal operasi OpenMP. Anda boleh membetulkan kod dalam Penyenaraian 2 dan hanya mencetak frasa Hai dunia! enam kali dengan menetapkan pembolehubah OMP_NUM_THREADS kepada 6, seperti yang ditunjukkan dalam Penyenaraian 5.

Penyenaraian 5. Pembolehubah persekitaran untuk mengkonfigurasi OpenMP
tintin$ eksport OMP_NUM_THREADS=6 tintin$ ./a.out Hello World! Hai dunia! Hai dunia! Hai dunia! Hai dunia! Hai dunia!

Kami melihat tiga aspek OpenMP: pragma pengkompil, API masa jalan dan pembolehubah persekitaran. Apakah yang berlaku apabila anda menggunakan pembolehubah persekitaran dengan API masa jalan? API mempunyai keutamaan yang lebih tinggi.

Kajian kes

OpenMP menggunakan teknologi selari tersirat dan boleh menggunakan pragma, fungsi eksplisit dan pembolehubah persekitaran untuk menghantar arahan kepada pengkompil. Mari lihat contoh yang jelas menunjukkan faedah menggunakan OpenMP. Lihat kod yang ditunjukkan dalam Penyenaraian 6.

Penyenaraian 6. Pemprosesan berurutan dalam gelung untuk
int main() ( int a, b; // ... kod permulaan untuk tatasusunan a dan b; int c; untuk (int i = 0; i< 1000000; ++i) c[i] = a[i] * b[i] + a * b; // ... выполняем некоторые действия с массивом c }

Jelas sekali, gelung for boleh disejajarkan dan diproses oleh beberapa teras pemproses sekali gus, kerana pengiraan nilai mana-mana elemen c[k] tidak bergantung dalam apa cara sekalipun pada elemen selebihnya bagi tatasusunan c. Penyenaraian 7 menunjukkan bagaimana anda boleh melakukan ini menggunakan OpenMP.

Penyenaraian 7. Pemprosesan selari dalam gelung for menggunakan selari untuk pragma
int main() ( int a, b; // ... kod untuk memulakan tatasusunan a dan b; int c; #pragma omp selari untuk untuk (int i = 0; i< 1000000; ++i) c[i] = a[i] * b[i] + a * b; // ... выполняем некоторые действия с массивом c }

Selari untuk pragma membantu mengagihkan beban kerja gelung for merentasi berbilang benang, yang setiap satu boleh diproses oleh teras pemproses yang berasingan; dengan itu masa pengiraan keseluruhan berkurangan dengan ketara. Ini disahkan dalam Penyenaraian 8.

Penyenaraian 8. Contoh menggunakan fungsi API omp_get_wtime
#termasuk #termasuk #termasuk #termasuk int main(int argc, char *argv) ( int i, nthreads; clock_t clock_timer; double wall_timer; double c; for (threads = 1; nthreads<=8; ++nthreads) { clock_timer = clock(); wall_timer = omp_get_wtime(); #pragma omp parallel for private(i) num_threads(nthreads) for (i = 0; i < 1000000; i++) c[i] = sqrt(i * 4 + i * 2 + i); std::cout << "threads: " << nthreads << " time on clock(): " << (double) (clock() - clock_timer) / CLOCKS_PER_SEC << " time on wall: " << omp_get_wtime() - wall_timer << "\n"; } }

Dalam Penyenaraian 8, kami mengukur masa pelaksanaan bagi gelung dalam sambil menambah bilangan utas. Fungsi API omp_get_wtime mengembalikan masa sebenar yang telah berlalu (dalam saat) sejak permulaan titik rujukan yang diberikan. Jadi omp_get_wtime() - wall_timer mengembalikan masa pelaksanaan sebenar gelung for. Panggilan sistem clock() digunakan untuk menganggarkan masa yang dibelanjakan oleh CPU untuk melaksanakan keseluruhan program, iaitu, kami menjumlahkan semua selang masa ini, dengan mengambil kira urutan, sebelum mendapat hasil akhir. Pada komputer Intel Core i7 saya, saya mendapat keputusan yang ditunjukkan dalam Penyenaraian 9.

Penyenaraian 9. Statistik untuk gelung dalam
benang: 1 kali pada jam(): 0.015229 masa pada dinding: 0.0152249 benang: 2 kali pada jam(): 0.014221 masa pada dinding: 0.00618792 benang: 3 kali pada jam(): 0.014541 masa pada dinding: 412 masa pada dinding: 4.02 masa pada dinding: 0.00618792 jam(): 0.014666 masa pada dinding: 0.00440478 benang: 5 masa pada jam(): 0.01594 masa pada dinding: 0.00359988 benang: 6 kali pada jam(): 0.015069 masa pada dinding: 0.0030368 masa pada dinding: 0.0030369 masa: 0.0030368 jam masa di dinding: 0.00258303 benang: 8 kali pada jam(): 0.01678 masa di dinding: 0.00237703

Walaupun masa CPU (masa pada jam) ternyata lebih kurang sama dalam semua kes (seperti yang sepatutnya, tidak mengambil kira masa tambahan yang dihabiskan untuk mencipta benang dan suis konteks), masa sebenar yang kita minati (masa di dinding) sentiasa berkurangan apabila kami menambah bilangan benang yang sepatutnya dilaksanakan secara selari oleh teras pemproses individu. Jadi, mari kita buat satu nota terakhir tentang sintaks pragma: #pragma selari untuk peribadi(i) bermakna pembolehubah gelung i dianggap sebagai memori setempat-benang; setiap benang mengandungi salinan pembolehubah ini sendiri. Pembolehubah tempatan benang tidak dimulakan.

Bahagian kod kritikal dalam OpenMP

Sudah tentu, anda faham bahawa anda tidak boleh mempercayai OpenMP sepenuhnya untuk mengendalikan bahagian kritikal kod secara automatik, bukan? Sudah tentu, anda tidak perlu membuat pengecualian bersama (mutex) secara eksplisit, tetapi kawasan kritikal masih perlu ditentukan. Sintaks diberikan dalam contoh berikut:

#pragma omp critical (nama bahagian pilihan) ( // 2 utas tidak boleh melaksanakan blok kod ini pada masa yang sama)

Kod yang mengikuti arahan kritikal pragma omp hanya boleh dilaksanakan dalam satu urutan pada masa tertentu. Selain itu, nama bahagian pilihan ialah pengecam global dan bahagian kritikal dengan pengecam yang sama tidak boleh diproses oleh dua utas pada masa yang sama. Mari lihat kod dalam Penyenaraian 10.

Penyenaraian 10. Berbilang bahagian kritikal dengan nama yang sama
#pragma omp critical (section1) ( myhashtable.insert("key1", "value1"); ) // ... ini mengandungi beberapa kod lain #pragma omp critical (section1) ( myhashtable.insert("key2", "value2 ");)

Melihat kod dalam penyenaraian ini, anda boleh menganggap bahawa dua sisipan ke dalam jadual cincang tidak akan berlaku pada masa yang sama kerana nama kawasan kritikal adalah sama. Ini sedikit berbeza daripada yang biasa anda lakukan semasa mengendalikan bahagian kritikal dalam pthread, yang cenderung menggunakan banyak penguncian (yang boleh membawa kepada kerumitan yang tidak perlu).

Kunci dan mutex dalam OpenMP

Menariknya, OpenMP mengandungi versi mutexnya sendiri (lagipun, OpenMP bukan sahaja pragma). Jadi, lihat jenis omp_lock_t, yang ditakrifkan dalam fail pengepala omp.h. Operasi mutex gaya pthread biasa dinilai kepada benar walaupun nama fungsi API adalah sama. Berikut ialah lima fungsi API yang perlu anda ketahui:

  • omp_init_lock: Fungsi API ini harus digunakan dahulu apabila mengakses jenis omp_lock_t dan bertujuan untuk pemula. Perlu diingatkan bahawa sejurus selepas permulaan, kunci akan berada dalam keadaan awal (tidak ditetapkan).
  • omp_destroy_lock: Memusnahkan kunci. Apabila fungsi API ini dipanggil, kunci mestilah dalam keadaan asalnya; ini bermakna anda tidak boleh memanggil omp_set_lock dan kemudian memusnahkan kunci.
  • omp_set_lock: menetapkan omp_lock_t, iaitu mengaktifkan mutex. Jika benang tidak dapat memperoleh kunci, ia akan terus menunggu sehingga peluang tersedia.
  • omp_test_lock: percubaan untuk mendapatkan kunci jika ada; mengembalikan 1 pada kejayaan dan 0 pada kegagalan. Fungsi ini ialah tidak menyekat, iaitu, ia tidak memaksa benang untuk menunggu kunci diperoleh.
  • omp_unset_lock: Menetapkan semula kunci kepada keadaan asalnya.

Penyenaraian 11 mengandungi pelaksanaan mudah baris gilir satu benang lama, dipertingkatkan untuk mengendalikan berbilang utas menggunakan kunci OpenMP. Sila ambil perhatian bahawa contoh ini bukanlah kes penggunaan serba terbaik dan disediakan semata-mata untuk menunjukkan keupayaan.

Penyenaraian 11. Meningkatkan baris gilir satu benang dengan OpenMP
#termasuk #include "myqueue.h" class omp_q: public myqueue ( awam: typedef myqueue asas; omp_q() ( omp_init_lock(&lock); ) ~omp_q() ( omp_destroy_lock(&lock); ) bool push(const int& value) ( ​​​​omp_set_lock(&lock); bool result = this->base::push(value); omp_unset_lock( &lock); return result; ) bool trypush(const int& value) ( ​​​​hasil bool = omp_test_lock(&lock); jika (hasil) ( result = result && this->base::push(value); omp_unset_lock(&lock ); ) return result; ) //begitu juga untuk pop private: omp_lock_t lock; );

Kunci bersarang

Jenis kunci lain dalam OpenMP ialah pelbagai kunci omp_nest_lock_t. Ia serupa dengan omp_lock_t tetapi mempunyai faedah tambahan iaitu kunci itu boleh diperoleh beberapa kali oleh benang yang memegangnya. Setiap kali kunci bersarang diperoleh oleh benang yang menahannya menggunakan omp_set_nest_lock , pembilang kunci dalaman dinaikkan. Kunci dilepaskan oleh benang penahan apabila satu atau lebih panggilan ke omp_unset_nest_lock mengurangkan pembilang kunci dalaman kepada 0. Fungsi API berikut digunakan untuk berfungsi dengan omp_nest_lock_t:

  • omp_init_nest_lock(omp_nest_lock_t*): Menetapkan kaunter sarang dalaman kepada 0 .
  • omp_destroy_nest_lock(omp_nest_lock_t*): Memusnahkan kunci. Memanggil fungsi API ini untuk kunci dengan nilai pembilang selain daripada sifar menghasilkan hasil yang tidak dapat diramalkan.
  • omp_set_nest_lock(omp_nest_lock_t*): Sama seperti omp_set_lock kecuali benang penahan boleh memanggilnya beberapa kali.
  • omp_test_nest_lock(omp_nest_lock_t*): ialah versi tidak menyekat fungsi API omp_set_nest_lock.
  • omp_unset_nest_lock(omp_nest_lock_t*): Melepaskan kunci apabila pembilang kunci dalaman mencapai 0. Dalam kes lain, setiap panggilan ke fungsi API ini mengurangkan nilai kaunter.

Kawalan terperinci penyiapan tugas

Kami telah melihat bahawa blok kod yang mengikuti arahan selari pragma omp diproses secara selari oleh semua benang. Kod dalam blok ini juga boleh dibahagikan kepada kategori yang akan dilaksanakan dalam urutan tertentu. Mari lihat kod dalam Penyenaraian 12.

Penyenaraian 12. Menggunakan bahagian selari pragma
int main() ( #pragma omp parallel ( cout<< "Это выполняется во всех потоках\n"; #pragma omp sections { #pragma omp section { cout << "Это выполняется параллельно\n"; } #pragma omp section { cout << "Последовательный оператор 1\n"; cout << "Это всегда выполняется после оператора 1\n"; } #pragma omp section { cout << "Это тоже выполняется параллельно\n"; } } } }

Kod sebelum arahan bahagian pragma omp dan serta-merta mengikuti arahan selari pragma omp diproses secara selari oleh semua urutan. Menggunakan arahan bahagian pragma omp, kod yang mengikutinya dibahagikan kepada subseksyen berasingan. Setiap blok bahagian pragma omp boleh dilaksanakan oleh benang yang berasingan. Walau bagaimanapun, pernyataan individu dalam blok bahagian sentiasa dilaksanakan secara berurutan. Penyenaraian 13 menunjukkan keputusan menjalankan kod dalam Penyenaraian 12.

Penyenaraian 13. Keputusan pelaksanaan kod daripada Penyenaraian 12
tintin$ ./a.out Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan dalam semua utas Ini berjalan selari Penyataan berurutan 1 Ini juga dilaksanakan secara selari Ini sentiasa dilaksanakan selepas pernyataan 1

Dalam Penyenaraian 13, kita sekali lagi melihat 8 utas yang pada mulanya dicipta. Tiga daripada lapan utas sudah memadai untuk memproses blok bahagian pragma omp. Di dalam bahagian kedua, kami menentukan susunan penyataan output teks dilaksanakan. Inilah titik penggunaan bahagian pragma. Jika perlu, anda boleh menentukan susunan blok kod dilaksanakan.

Arahan Firstprivate dan lastprivate bersama dengan gelung selari

Dalam artikel ini, saya telah menunjukkan cara mengisytiharkan memori tempatan benang menggunakan arahan peribadi. Tetapi bagaimana untuk memulakan pembolehubah tempatan benang? Mungkin menyegerakkannya dengan nilai pembolehubah utas utama sebelum meneruskan lebih jauh? Dalam kes sedemikian, arahan persendirian pertama sangat berguna.

arahan peribadi pertama

Menggunakan arahan firstprivate(variable), anda boleh memulakan pembolehubah pada thread kepada apa-apa nilai yang ada pada thread utama. Mari lihat kod dari Penyenaraian 14.

Penyenaraian 14. Menggunakan pembolehubah setempat-benang yang tidak disegerakkan dengan utas utama
#termasuk #termasuk int main() ( int idx = 100; #pragma omp parallel private(idx) ( printf("Pada benang %d idx = %d\n", omp_get_thread_num(), idx); ) )

Inilah hasil yang saya dapat (hasil anda mungkin berbeza-beza).

Dalam strim 1 idx = 1 Dalam strim 5 idx = 1 Dalam strim 6 idx = 1 Dalam strim 0 idx = 0 Dalam strim 4 idx = 1 Dalam strim 7 idx = 1 Dalam strim 2 idx = 1 Dalam strim 3 idx = 1

Penyenaraian 15 mengandungi kod menggunakan arahan persendirian pertama. Seperti yang dijangkakan, output menunjukkan bahawa pembolehubah idx ditetapkan kepada 100 dalam semua urutan.

Penyenaraian 15. Menggunakan arahan persendirian pertama untuk memulakan pembolehubah setempat-benang
#termasuk #termasuk int main() ( int idx = 100; #pragma omp parallel firstprivate(idx) ( printf("Pada benang %d idx = %d\n", omp_get_thread_num(), idx); )

Juga ambil perhatian bahawa kaedah omp_get_thread_num() telah digunakan untuk mengakses ID urutan. Pengecam ini berbeza daripada output pengecam oleh arahan atas sistem pengendalian Linux®, dan skema ini hanyalah satu cara untuk OpenMP menjejaki bilangan utas. Jika anda bercadang untuk menggunakan arahan persendirian pertama dalam kod C++, maka perhatikan ciri lain: pembolehubah yang digunakan oleh arahan persendirian pertama ialah pembina salinan untuk memulakan dirinya daripada pembolehubah utas utama, jadi jika pembina salinan adalah peribadi untuk kelas anda, ini boleh membawa kepada akibat yang tidak menyenangkan. Sekarang mari kita beralih kepada arahan peribadi terakhir, yang dalam banyak cara adalah bahagian lain daripada syiling.

arahan peribadi terakhir

Daripada menyegerakkan pembolehubah thread-tempatan dengan data utas utama, kami akan menyegerakkan pembolehubah utas utama dengan data yang akan diperolehi hasil daripada gelung terakhir. Penyenaraian 16 menjalankan selari untuk gelung.

Penyenaraian 16. Selari untuk gelung tanpa penyegerakan data dengan utas utama
#termasuk #termasuk int main() ( int idx = 100; int main_var = 2120; #pragma omp selari untuk private(idx) untuk (idx = 0; idx< 12; ++idx) { main_var = idx * idx; printf("В потоке %d idx = %d main_var = %d\n", omp_get_thread_num(), idx, main_var); } printf("Возврат в главный поток со значением переменной main_var = %d\n", main_var); }

Pada mesin 8-teras saya, OpenMP mencipta enam utas untuk selari untuk blok. Setiap benang pula mempunyai dua lelaran dalam gelung. Nilai akhir pembolehubah main_var bergantung pada utas yang dilaksanakan terakhir dan, oleh itu, pada nilai pembolehubah idx dalam utas itu. Dalam erti kata lain, nilai pembolehubah main_var tidak bergantung pada nilai terakhir pembolehubah idx, tetapi bergantung pada nilai pembolehubah idx terkandung dalam utas yang terakhir dilaksanakan. Contoh ini ditunjukkan dalam Penyenaraian 17.

Penyenaraian 17. Kebergantungan nilai pembolehubah main_var pada urutan yang terakhir dilaksanakan
Dalam thread 4 idx = 8 main_var = 64 Dalam thread 2 idx = 4 main_var = 16 Dalam thread 5 idx = 10 main_var = 100 Dalam thread 3 idx = 6 main_var = 36 Dalam thread 0 idx = 0 main_var = 0 Dalam thread 1 idx = 2 main_var = 4 Dalam thread 4 idx = 9 main_var = 81 Dalam thread 2 idx = 5 main_var = 25 Dalam thread 5 idx = 11 main_var = 121 Dalam thread 3 idx = 7 main_var = 49 Dalam thread 0 idx = 1 main_var = 1 In utas 1 idx = 3 main_var = 9 Kembali ke utas utama dengan nilai pembolehubah main_var = 9

Jalankan kod dalam Penyenaraian 17 beberapa kali untuk memastikan bahawa nilai main_var pada utas utama sentiasa bergantung pada nilai idx pada utas terakhir yang dijalankan. Bagaimana jika anda perlu menyegerakkan nilai pembolehubah utas utama dengan nilai akhir pembolehubah idx dalam gelung? Di sinilah arahan terakhir persendirian berguna, seperti yang ditunjukkan dalam Penyenaraian 18. Seperti contoh sebelumnya, jalankan kod dalam Penyenaraian 18 beberapa kali dan anda akan melihat bahawa nilai akhir pembolehubah main_var pada utas utama ialah 121 (iaitu, nilai pembolehubah idx dalam lelaran terakhir gelung).

Penyenaraian 18. Penyegerakan menggunakan arahan peribadi terakhir
#termasuk #termasuk int main() ( int idx = 100; int main_var = 2120; #pragma omp selari untuk private(idx) lastprivate(main_var) untuk (idx = 0; idx< 12; ++idx) { main_var = idx * idx; printf("В потоке %d idx = %d main_var = %d\n", omp_get_thread_num(), idx, main_var); } printf("Возврат в главный поток со значением переменной main_var = %d\n", main_var); }

Penyenaraian 19 menunjukkan keputusan menjalankan kod dalam Penyenaraian 18.

Penyenaraian 19. Keputusan pelaksanaan kod daripada Penyenaraian 18 (perhatikan bahawa main_var sentiasa ditetapkan kepada 121 pada utas utama)
Dalam thread 3 idx = 6 main_var = 36 Dalam thread 2 idx = 4 main_var = 16 Dalam thread 1 idx = 2 main_var = 4 Dalam thread 4 idx = 8 main_var = 64 Dalam thread 5 idx = 10 main_var = 100 Dalam thread 3 idx = 7 main_var = 49 Dalam thread 0 idx = 0 main_var = 0 Dalam thread 2 idx = 5 main_var = 25 Dalam thread 1 idx = 3 main_var = 9 Dalam thread 4 idx = 9 main_var = 81 Dalam thread 5 idx = 11 main_var = 121 V utas 0 idx = 1 main_var = 1 Kembali ke utas utama dengan nilai pembolehubah main_var = 121

Satu nota terakhir: untuk menyokong operator lastprivate dalam objek C++, kelas yang sepadan mesti mempunyai kaedah operator= awam yang tersedia.

Gabungkan isihan dalam OpenMP

Mari lihat contoh kehidupan sebenar di mana OpenMP mengurangkan masa pelaksanaan tugas. Mari kita ambil versi prosedur isihan gabungan yang tidak begitu dioptimumkan, cukup untuk menunjukkan faedah menggunakan OpenMP. Contoh ini ditunjukkan dalam Penyenaraian 20.

Penyenaraian 20. Gabungkan isihan dalam OpenMP
#termasuk #termasuk #termasuk menggunakan ruang nama std; vektor bergabung (vektor const & kiri, vektor const & kanan) (vektor hasil; unsigned left_it = 0, right_it = 0; while(left_it< left.size() && right_it < right.size()) { if(left < right) { result.push_back(left); left_it++; } else { result.push_back(right); right_it++; } } // Занесение оставшихся данных из обоих векторов в результирующий while(left_it < left.size()) { result.push_back(left); left_it++; } while(right_it < right.size()) { result.push_back(right); right_it++; } return result; } vectormergesort(vektor & vec, int threads) ( // Syarat penamatan: senarai diisih sepenuhnya jika // ia mengandungi hanya satu elemen. if(vec.size() == 1) ( return vec; ) // Tentukan lokasi tengah elemen dalam vektor std ::vector ::iterator middle = vec.begin() + (vec.size() / 2); vektor kiri(vec.begin(), tengah); vektor kanan(tengah, vec.end()); // Lakukan pengisihan gabungan pada dua vektor yang lebih kecil jika (benang > 1) ( #pragma omp bahagian selari ( #pragma omp bahagian ( kiri = mergesort(kiri, benang/2); ) #pragma omp bahagian ( kanan = mergesort(kanan, benang - benang/2); ) ) ) lain ( kiri = mergesort(kiri, 1); kanan = mergesort(kanan, 1); ) return merge(kiri, kanan); ) int main() ( vektor v(1000000); untuk (panjang i=0; i<1000000; ++i) v[i] = (i * i) % 1000000; v = mergesort(v, 1); for (long i=0; i<1000000; ++i) cout << v[i] << "\n"; }

Apabila menggunakan 8 utas untuk melaksanakan prosedur isihan cantum, masa pelaksanaan dikurangkan daripada 3.7 saat (menggunakan satu utas) kepada 2.1 saat. Di sini anda hanya perlu berhati-hati dengan bilangan benang. Saya bermula dengan 8 utas, tetapi faedah sebenar daripada menggunakannya mungkin berbeza-beza bergantung pada konfigurasi sistem. Jika bilangan utas tidak dihadkan secara eksplisit, ratusan jika tidak ribuan utas boleh dibuat, yang berkemungkinan besar akan merendahkan prestasi sistem. Selain itu, apabila bekerja dengan kod isihan gabungan, adalah berguna untuk menggunakan bahagian pragma, yang telah dibincangkan sebelum ini.

Kesimpulan

Di sinilah saya mengakhiri artikel. Kami telah membincangkan pragma selari dan cara mencipta benang secara meluas, melihat bagaimana OpenMP mengurangkan masa pelaksanaan tugas dan membenarkan penyegerakan dan kawalan fleksibel, dan melihat contoh praktikal menggunakan isihan gabungan . Sudah tentu, masih banyak yang perlu dipelajari, dan tempat terbaik untuk mempelajari ini ialah tapak Web Projek OpenMP. Semua maklumat tambahan boleh didapati di bahagian.

OpenMP memudahkan untuk mencipta program selari untuk sistem memori yang dikongsi (berbilang teras dan berbilang pemproses). Dalam artikel ini saya akan bercakap tentang cara mendayakan OpenMP dalam persekitaran pengaturcaraan yang paling biasa - Visual Studio. Menurut keluaran rasmi Microsoft, OpenMP hanya disokong dalam versi Profesional persekitaran pembangunan Visual Studio 2005/2008/2010. Walau bagaimanapun, Visual Studio Express percuma mempunyai pengkompil yang sama seperti versi Profesional. Oleh itu, selepas sedikit pengubahsuaian dengan fail, program OpenMP selari akan menyusun dan, yang paling penting, berfungsi walaupun dalam Visual Studio Express.

OpenMP daripada Microsoft dilaksanakan melalui komponen berikut:

  1. Pengkompil C++ disertakan dengan Visual Studio;
  2. fail pengepala omp.h;
  3. perpustakaan peringkat kompilasi: vcomp.lib dan vcompd.lib (yang terakhir digunakan untuk penyahpepijatan);
  4. Pustaka masa jalan: vcomp90.dll dan vcomp90d.dll. Nombor dalam nama mungkin berbeza-beza: dalam Visual Studio 2005, bukannya 90, nombornya ialah 80.

Visual Studio Express percuma tidak mengandungi perpustakaan yang disenaraikan.

OpenMP dan Visual Studio Express

Jika anda ingin mencipta program OpenMP selari di bawah Windows, maka cara yang paling mudah ialah menggunakan Visual Studio 2005/2008/2010 Professional. Izinkan saya mengingatkan anda bahawa ia adalah percuma untuk pelajar sarjana dan siswazah. Sebagai alternatif, anda boleh membeli Visual Studio Professional dengan harga $600 (sudah tentu, terdapat pilihan ketiga, tetapi kami tidak akan membincangkannya).

Jika anda memasang versi Profesional pada komputer anda, teruskan ke bahagian seterusnya artikel. Dalam bahagian ini, kami akan mempertimbangkan kes apabila atas sebab tertentu anda terpaksa menggunakan Visual Studio Express.

Visual Studio Express ialah versi percuma Visual Studio yang dilucutkan. Kami akan berminat dengan versi 2008. Anda boleh memuat turunnya dari sini: http://www.microsoft.com/exPress/download/. Sememangnya, kami akan memprogramkan dalam C++, jadi pilih Visual C++ 2008.

Pemasang akan memuat turun data daripada Internet (kira-kira 100 megabait), jadi anda boleh menjimatkan beberapa lebar jalur dengan melumpuhkan pemasangan Microsoft Silverlight dan Microsoft SQL Server jika anda tidak memerlukannya.

Selepas memasang Visual Studio Express, kami perlu menambah komponen OpenMP padanya. Cara yang sah dan percuma untuk melakukan ini ialah memasang Windows SDK untuk Windows Server 2008 dan .NET Framework 3.5. Semasa pemasangan pakej perisian ini, Visual Studio akan dikemas kini. Proses kemas kini tidak melihat versi Visual Studio yang telah anda pasang (Express atau Professional), jadi semasa pemasangan ia akan "secara tidak sengaja" menambah komponen yang hilang.

Memandangkan kami memasang Windows SDK hanya demi OpenMP, kami tidak memerlukan gigabait dokumentasi yang disertakan bersama kit. Saya syorkan tinggalkan elemen berikut sahaja:

Rajah 1. Komponen SDK yang kami perlukan

Malangnya, SDK tidak termasuk perpustakaan vcomp90d.dll, jadi pada masa ini anda hanya boleh menjalankan program OpenMP yang disusun dalam mod Keluaran dalam Visual Studio Express. Saya menemui cara untuk mengatasi had ini, baca tentangnya dengan lebih lanjut (bahagian "Menyahpepijat program OpenMP dalam Visual Studio Express").

Menggunakan OpenMP dalam Visual Studio

Setelah anda melengkapkan langkah dalam bahagian sebelumnya, tidak kira versi Visual Studio yang anda gunakan. Saya akan menunjukkan kepada anda langkah demi langkah cara membuat projek dengan sokongan OpenMP dalam persekitaran pembangunan ini. Pertama sekali, anda perlu melancarkan Visual Studio dan pilih Fail → Baru → Projek... Tetingkap penciptaan projek akan muncul. Pilih jenis projek "Win32", templat - "Aplikasi Konsol Win32". Masukkan nama projek yang bermakna, pilih folder untuk menyimpan projek, nyahtanda "Buat direktori untuk penyelesaian":

Rajah 2. Tetingkap penciptaan projek

Klik butang "OK", tetingkap untuk menyediakan projek masa depan akan muncul. Pilih tab "Tetapan Aplikasi", dan hidupkan kotak semak "Projek kosong":

Rajah 3. Tetingkap tetapan projek masa hadapan

Dengan mengklik butang "Selesai", projek akan dibuat. Tidak akan ada perubahan yang kelihatan pada tetingkap Visual Studio utama. Hanya nama projek dalam tajuk tetingkap memberitahu kami bahawa kami sedang bekerja dengan projek.

Sekarang klik Projek → Tambah Item Baru, tetingkap untuk menambah item pada projek akan muncul. Tambahkan fail .cpp pada projek:

Rajah 4. Tetingkap untuk menambah elemen pada projek

Selepas ini, anda akan diberikan tetingkap untuk memasukkan kod sumber program. Kami akan menjalankan ujian pada kod berikut, yang menyemak pelbagai aspek fungsi OpenMP:

#termasuk #termasuk menggunakan ruang nama std; int main(int argc, char **argv) ( int test(999); omp_set_num_threads(2); #pragma omp parallel reduction(+:test) ( #pragma omp critical cout<< "test = " << test << endl; } return EXIT_SUCCESS; } Листинг 1. Простейшая программа, использующая OpenMP

Mulakan program dengan mengklik Debug→Start Without Debugging. Jika semuanya dilakukan dengan betul, program akan menyusun (jika ia bertanya kepada anda sama ada untuk menyusun, klik Ya), maka ia akan berjalan dan mencetak ujian = 999:

Rajah 5. Keputusan program daripada Penyenaraian 1

"Macam mana?! - anda berkata, "Lagipun, program harus mempunyai output sifar, dan dua kali!" Hakikatnya OpenMP belum lagi didayakan, dan oleh itu arahan yang sepadan telah diabaikan oleh pengkompil.

Untuk mendayakan OpenMP, klik Projek → OMP Properties (OMP ialah nama projek daripada contoh saya). Di bahagian atas sebelah kiri tetingkap yang muncul, pilih "Semua Konfigurasi" dan dalam bahagian Konfigurasi → C/C++ → Bahasa, dayakan "Sokongan OpenMP":

Rajah 6. Dayakan OpenMP dalam sifat projek

Selepas ini, jalankan program sekali lagi dengan mengklik Debug→Start Without Debugging. Kali ini program akan mencetak ujian = 0 dua kali:

Rajah 7. Hasil daripada menjalankan program daripada Penyenaraian 1 dengan OpenMP didayakan

Hooray! OpenMP berfungsi.

Catatan. Jika anda menggunakan Visual Studio Express, kemudian pilih konfigurasi semasa "Lepaskan", jika tidak, ia tidak akan berfungsi (baca selanjutnya):

Rajah 8. Memilih konfigurasi semasa

Seperti yang dinyatakan sebelum ini, walaupun selepas memasang Windows SDK, kami tidak akan mempunyai pustaka vcomp90d.dll yang diperlukan untuk penyahpepijatan, jadi kami belum boleh menyahpepijat atur cara OpenMP dalam Visual Studio Express. Hanya menyalin pustaka vcomp90.dll sedia ada dan menamakannya kepada vcomp90d.dll tidak akan berfungsi, kerana checksum dan versi yang dinyatakan dalam manifes yang dibenamkan dalam fail exe tidak akan sepadan. Oleh itu, kami akan "menggali" dari sisi yang bertentangan.

Apabila disusun dalam konfigurasi Nyahpepijat, fail pengepala omp.h memerlukan perpustakaan vcompd.lib (kami ada), yang seterusnya memerlukan vcomp90d.dll (tiada). Lesen tidak membenarkan kami menggunakan fail pengepala diubah suai daripada Microsoft dalam aplikasi, jadi bukannya mengubah suai omp.h, kami akan memasukkannya ke dalam program kami seperti berikut supaya ia tidak meneka bahawa mod nyahpepijat didayakan:

#termasuk #ifdef _DEBUG #undef _DEBUG #include #define_DEBUG #else #include #endif menggunakan ruang nama std; int main(int argc, char **argv) ( int test(999); omp_set_num_threads(2); #pragma omp parallel reduction(+:test) ( #pragma omp critical cout<< "test = " << test << endl; } return EXIT_SUCCESS; } Листинг 2. Включаем omp.h «хитрым» способом

Tindakan di atas tidak mencukupi untuk semuanya berfungsi (setakat ini kami hanya membetulkan manifes yang terbina dalam program). Hakikatnya ialah Visual Studio dalam mod nyahpepijat masih secara automatik (disebabkan OpenMP didayakan) memaut vcompd.lib, yang memerlukan vcomp90d.dll. Untuk membetulkannya, pergi ke tetapan projek sekali lagi (Projek → OMP Properties), kali ini pilih Konfigurasi: "Nyahpepijat". Dalam bahagian Configuration Properties→Linker→Input, nyatakan bahawa vcompd.lib tidak perlu dipautkan, tetapi vcompd.lib:

Rajah 9. Gantikan perpustakaan dalam sifat projek

Mari kita semak sama ada penyahpepijatan berfungsi dan sama ada program itu benar-benar berjalan selari. Letakkan titik putus pada baris yang memaparkan nilai pembolehubah. Untuk melakukan ini, klik kiri pada bar kelabu di sebelah kiri kod sumber:

Rajah 10. Titik putus

Selepas ini, jalankan program dalam mod nyahpepijat: Nyahpepijat→Mulakan Nyahpepijat (jangan lupa untuk mengembalikan konfigurasi "Nyahpepijat" semasa, lihat Rajah 8). Program akan bermula dan berhenti serta-merta di titik putus. Dalam tab "Benang" kita melihat bahawa program itu sebenarnya berjalan menggunakan dua utas:

Rajah 11. Menyahpepijat atur cara OpenMP dalam Visual Studio Express

OpenMP ialah standard antara muka pengaturcaraan aplikasi untuk sistem memori kongsi selari. Menyokong bahasa C, C++, Fortran.

Model program OpenMP

Model program selari dalam OpenMP boleh dirumuskan seperti berikut:

  • Program ini terdiri daripada bahagian bersiri dan selari (Rajah 2.1).
  • Pada saat permulaan masa, utas utama dicipta yang melaksanakan bahagian berturut-turut program.
  • Apabila memasuki bahagian selari, operasi dilakukan garpu, menjana keluarga benang. Setiap utas mempunyai pengecam berangka tersendiri (benang utama ialah 0). Apabila gelung disejajarkan, semua benang selari melaksanakan kod yang sama. Secara umum, benang boleh melaksanakan kepingan kod yang berbeza.
  • Apabila keluar dari bahagian selari, operasi dilakukan sertai.Pelaksanaan semua utas kecuali yang utama berakhir.

OpenMP terdiri daripada komponen berikut:

  • Arahan penyusun- digunakan untuk mencipta benang, mengagihkan kerja antara benang dan menyegerakkannya. Arahan disertakan dalam kod sumber program.
  • Rutin perpustakaan masa jalan- digunakan untuk menetapkan dan mentakrifkan atribut aliran. Panggilan ke rutin ini disertakan dalam kod sumber program.
  • Pembolehubah Persekitaran- digunakan untuk mengawal tingkah laku program selari. Pembolehubah persekitaran ditetapkan untuk persekitaran pelaksanaan program selari dengan arahan yang sesuai (contohnya, arahan shell pada sistem pengendalian UNIX).

Penggunaan arahan pengkompil dan rutin perpustakaan runtime tertakluk kepada peraturan yang berbeza-beza antara bahasa pengaturcaraan. Set peraturan sedemikian dipanggil terikat bahasa.

Pengikat bahasa Fortran

Dalam program Fortran arahan penyusun, nama subrutin dan pembolehubah persekitaran bermula dengan OMP. Format arahan penyusun:

(!|C|*)Arahan $OMP [operator_1[, operator_2, ...]]

Arahan bermula pada kedudukan baris pertama (format teks Fortran 77 tetap) atau sewenang-wenangnya (format percuma). Adalah mungkin untuk meneruskan arahan pada baris seterusnya, dalam hal ini peraturan standard dalam versi bahasa ini untuk menunjukkan baris sambungan terpakai (aksara bukan kosong di kedudukan keenam untuk format rekod tetap dan ampersand untuk format percuma).

Contoh program Fortran menggunakan OpenMP

atur cara omp_example integer i, k, N nyata*4 jumlah, h, x cetak *, "Sila, taipkan N:" baca *, N h = 1.0 / N jumlah = 0.0 C$OMP SELARI JADUAL JUGA (STATIK) PENGURANGAN( +:sum) do i = 1, N x = i * h sum = sum + 1.e0 * h / (1.e0 + x**2) enddo print *, 4.0 * sum end