A. 예제
다음은 이 문서에 정의된 구문의 예입니다. 지시문 다음의 문은 필요한 경우에만 복합이며, 비복합 문은 앞에 오는 지시문에서 들여쓰기됩니다.
A.1 간단한 병렬 루프
다음 예제에서는 지시문에 대한 병렬을 사용하여 루프를 병렬화하는 방법을 보여 줍니다. 루프 반복 변수는 기본적으로 private이므로 private 절에서 명시적으로 지정할 필요가 없습니다.
#pragma omp parallel for
for (i=1; i<n; i++)
b[i] = (a[i] + a[i-1]) / 2.0;
A.2 조건부 컴파일
다음 예제에서는 OpenMP 매크로 _OPENMP를 사용하여 조건부 컴파일을 사용하는 방법을 보여 줍니다. OpenMP 컴파일을 사용하면 _OPENMP
매크로가 정의됩니다.
# ifdef _OPENMP
printf_s("Compiled by an OpenMP-compliant implementation.\n");
# endif
정의된 전처리기 연산자를 사용하면 둘 이상의 매크로를 단일 지시문으로 테스트할 수 있습니다.
# if defined(_OPENMP) && defined(VERBOSE)
printf_s("Compiled by an OpenMP-compliant implementation.\n");
# endif
A.3 병렬 영역
병렬 지시문은 정교하지 않은 수준의 병렬 프로그램에서 사용할 수 있습니다. 다음 예제에서 병렬 영역의 각 스레드는 스레드 번호에 따라 작업할 전역 배열 x
의 일부를 결정합니다.
#pragma omp parallel shared(x, npoints) private(iam, np, ipoints)
{
iam = omp_get_thread_num();
np = omp_get_num_threads();
ipoints = npoints / np;
subdomain(x, iam, ipoints);
}
A.4 nowait 절
병렬 영역 내에 독립 루프가 많이 있는 경우, 다음과 같이 nowait 절을 사용하여 for
지시문 끝의 암시적 장벽을 방지할 수 있습니다.
#pragma omp parallel
{
#pragma omp for nowait
for (i=1; i<n; i++)
b[i] = (a[i] + a[i-1]) / 2.0;
#pragma omp for nowait
for (i=0; i<m; i++)
y[i] = sqrt(z[i]);
}
A.5 critical 지시문
다음 예제에는 몇 가지 critical 지시문이 포함되어 있습니다. 이 예제에서는 작업을 큐에서 제거하고 작업하는 큐 모델을 보여 줍니다. 여러 스레드가 동일한 작업을 큐에서 제거하는 것을 방지하려면 큐에서 제거 작업이 critical
섹션에 있어야 합니다. 이 예제의 두 큐는 독립적이므로 xaxi 및 yaxis이라는 서로 다른 이름의 critical
지시문으로 보호 됩니다.
#pragma omp parallel shared(x, y) private(x_next, y_next)
{
#pragma omp critical ( xaxis )
x_next = dequeue(x);
work(x_next);
#pragma omp critical ( yaxis )
y_next = dequeue(y);
work(y_next);
}
A.6 lastprivate 절
루프의 마지막 반복이 변수에 할당하는 값에 따라 올바른 실행이 달라지는 경우가 있습니다. 이러한 프로그램은 루프가 순차적으로 실행될 때와 동일한 변수 값이 되도록 lastprivate 절에 대한 인수와 같은 모든 변수를 나열해야 합니다.
#pragma omp parallel
{
#pragma omp for lastprivate(i)
for (i=0; i<n-1; i++)
a[i] = b[i] + b[i+1];
}
a[i]=b[i];
앞의 예제에서 병렬 영역의 끝에 있는 i
의 값은 순차적 사례처럼 n-1
와 같습니다.
A.7 reduction 절
다음 예제에서는 reduction 절을 보여 줍니다.
#pragma omp parallel for private(i) shared(x, y, n) \
reduction(+: a, b)
for (i=0; i<n; i++) {
a = a + x[i];
b = b + y[i];
}
A.8 병렬 섹션
다음 예제(섹션 2.4.2의 경우)에서는 xaxis, yaxis 및 zaxis 함수를 동시에 실행할 수 있습니다. 첫 번째 section
지시문은 선택 사항입니다. 모든 section
지시문은 parallel sections
구문의 어휘 범위에 나타나야 합니다.
#pragma omp parallel sections
{
#pragma omp section
xaxis();
#pragma omp section
yaxis();
#pragma omp section
zaxis();
}
A.9 단일 지시문
다음 예제에서는 단일 지시문을 보여 줍니다. 이 예제에서는 하나의 스레드(일반적으로 single
지시문과 조우하는 첫 번째 스레드)만 진행률 메시지를 출력합니다. 사용자는 어떤 스레드가 single
섹션을 실행할지 가정해서는 안 됩니다. 다른 모든 스레드는 single
섹션을 건너뛰고 single
구문의 끝에 있는 장벽에서 중지됩니다. 다른 스레드가 single
섹션을 실행하는 스레드를 기다리지 않고 진행할 수 있는 경우, single
지시문에 nowait
절을 지정할 수 있습니다.
#pragma omp parallel
{
#pragma omp single
printf_s("Beginning work1.\n");
work1();
#pragma omp single
printf_s("Finishing work1.\n");
#pragma omp single nowait
printf_s("Finished work1 and beginning work2.\n");
work2();
}
A.10 순차 순서 지정
순서가 지정된 섹션 은 병렬로 수행된 작업의 출력을 순차적으로 정렬하는 데 유용합니다. 다음 프로그램은 순차적으로 인덱스를 출력합니다.
#pragma omp for ordered schedule(dynamic)
for (i=lb; i<ub; i+=st)
work(i);
void work(int k)
{
#pragma omp ordered
printf_s(" %d", k);
}
A.11 고정 스레드 수
일부 프로그램은 올바르게 실행되기 위해 미리 지정된 고정된 수의 스레드를 사용합니다. 스레드 수의 동적 조정에 대한 기본값 설정은 구현 정의이므로 이러한 프로그램은 이식성을 유지하기 위해 동적 스레드 기능을 사용하지 않고 스레드 수를 명시적으로 설정할 수 있습니다. 다음 예제에서는 omp_set_dynamic 및 omp_set_num_threads를 사용하여 이 작업을 수행하는 방법을 보여 줍니다.
omp_set_dynamic(0);
omp_set_num_threads(16);
#pragma omp parallel shared(x, npoints) private(iam, ipoints)
{
if (omp_get_num_threads() != 16)
abort();
iam = omp_get_thread_num();
ipoints = npoints/16;
do_by_16(x, iam, ipoints);
}
이 예제에서는 프로그램이 16개의 스레드로 실행되는 경우에만 올바르게 실행됩니다. 구현에서 16개의 스레드를 지원할 수 없는 경우, 이 예제의 동작은 구현 정의입니다.
병렬 영역을 실행하는 스레드 수는 동적 스레드 설정에 관계없이 병렬 영역 동안 일정하게 유지됩니다. 동적 스레드 메커니즘은 병렬 영역의 시작 부분에 사용할 스레드 수를 결정하고 영역 기간 동안 일정하게 유지합니다.
A.12 atomic 지시문
다음 예제에서는 atomic지시문을 사용하여 경합 조건(여러 스레드에서 x 요소의 동시 업데이트)을 방지합니다.
#pragma omp parallel for shared(x, y, index, n)
for (i=0; i<n; i++)
{
#pragma omp atomic
x[index[i]] += work1(i);
y[i] += work2(i);
}
이 예제에서 atomic
지시문을 사용하면 x의 서로 다른 두 요소에 대한 업데이트가 병렬로 수행되도록 할 수 있다는 장점이 있습니다. 대신 critical 지시문을 사용하는 경우 x의 요소에 대한 모든 업데이트가 직렬로 실행됩니다(보장된 순서는 아님).
atomic
지시문은 바로 다음 C 또는 C++ 문에만 적용됩니다. 따라서 이 예제에서는 y의 요소가 atomic으로 업데이트되지 않습니다.
A.13 목록이 있는 flush 지시문
다음 예제에서는 스레드 쌍 간의 특정 개체의 점 대 점 동기화에 flush
지시문을 사용합니다.
int sync[NUMBER_OF_THREADS];
float work[NUMBER_OF_THREADS];
#pragma omp parallel private(iam,neighbor) shared(work,sync)
{
iam = omp_get_thread_num();
sync[iam] = 0;
#pragma omp barrier
// Do computation into my portion of work array
work[iam] = ...;
// Announce that I am done with my work
// The first flush ensures that my work is
// made visible before sync.
// The second flush ensures that sync is made visible.
#pragma omp flush(work)
sync[iam] = 1;
#pragma omp flush(sync)
// Wait for neighbor
neighbor = (iam>0 ? iam : omp_get_num_threads()) - 1;
while (sync[neighbor]==0)
{
#pragma omp flush(sync)
}
// Read neighbor's values of work array
... = work[neighbor];
}
A.14 목록이 없는 flush 지시문
다음 예제(섹션 2.6.5용)는 목록이 없으며 flush
지시문의 영향을 받는 공유 개체와 영향을 받지 않는 공유 개체를 구분합니다.
// omp_flush_without_list.c
#include <omp.h>
int x, *p = &x;
void f1(int *q)
{
*q = 1;
#pragma omp flush
// x, p, and *q are flushed
// because they are shared and accessible
// q is not flushed because it is not shared.
}
void f2(int *q)
{
#pragma omp barrier
*q = 2;
#pragma omp barrier
// a barrier implies a flush
// x, p, and *q are flushed
// because they are shared and accessible
// q is not flushed because it is not shared.
}
int g(int n)
{
int i = 1, j, sum = 0;
*p = 1;
#pragma omp parallel reduction(+: sum) num_threads(10)
{
f1(&j);
// i, n and sum were not flushed
// because they were not accessible in f1
// j was flushed because it was accessible
sum += j;
f2(&j);
// i, n, and sum were not flushed
// because they were not accessible in f2
// j was flushed because it was accessible
sum += i + j + *p + n;
}
return sum;
}
int main()
{
}
A.15 사용된 스레드 수
다음 잘못된 예제를 참조하세요(섹션 3.1.2 용).
np = omp_get_num_threads(); // misplaced
#pragma omp parallel for schedule(static)
for (i=0; i<np; i++)
work(i);
omp_get_num_threads()
호출은 코드의 직렬 섹션에서 1을 반환하므로 np는 이전 예제에서 항상 1과 같습니다. 병렬 영역에 대해 배포될 스레드 수를 결정하려면 해당 호출은 병렬 영역 내에 있어야 합니다.
다음 예제에서는 스레드 수에 대한 쿼리를 포함하지 않고 이 프로그램을 재작성하는 방법을 보여 줍니다.
#pragma omp parallel private(i)
{
i = omp_get_thread_num();
work(i);
}
A.16 잠금
다음 예제(섹션 3.2용)에서는 잠금 함수에 대한 인수에 omp_lock_t
형식이 있어야 하며 플러시할 필요가 없습니다. 잠금 함수는 첫 번째 중요 섹션에 대한 항목을 기다리는 동안 스레드를 유휴 상태로 만들지만, 두 번째 섹션에 대한 입력을 기다리는 동안 다른 작업을 수행합니다. omp_set_lock
함수는 차단하지만, omp_test_lock
함수는 그렇지 않으며 skip()
에서의 작업을 수행하도록 허용합니다.
// omp_using_locks.c
// compile with: /openmp /c
#include <stdio.h>
#include <omp.h>
void work(int);
void skip(int);
int main() {
omp_lock_t lck;
int id;
omp_init_lock(&lck);
#pragma omp parallel shared(lck) private(id)
{
id = omp_get_thread_num();
omp_set_lock(&lck);
printf_s("My thread id is %d.\n", id);
// only one thread at a time can execute this printf
omp_unset_lock(&lck);
while (! omp_test_lock(&lck)) {
skip(id); // we do not yet have the lock,
// so we must do something else
}
work(id); // we now have the lock
// and can do the work
omp_unset_lock(&lck);
}
omp_destroy_lock(&lck);
}
A.17 중첩 가능 잠금
다음 예제(섹션 3.2용)에서는 중첩 가능 잠금을 사용하여 업데이트를 전체 구조체와 구조체의 멤버 중 하나에 동기화하는 방법을 보여 줍니다.
#include <omp.h>
typedef struct {int a,b; omp_nest_lock_t lck;} pair;
void incr_a(pair *p, int a)
{
// Called only from incr_pair, no need to lock.
p->a += a;
}
void incr_b(pair *p, int b)
{
// Called both from incr_pair and elsewhere,
// so need a nestable lock.
omp_set_nest_lock(&p->lck);
p->b += b;
omp_unset_nest_lock(&p->lck);
}
void incr_pair(pair *p, int a, int b)
{
omp_set_nest_lock(&p->lck);
incr_a(p, a);
incr_b(p, b);
omp_unset_nest_lock(&p->lck);
}
void f(pair *p)
{
extern int work1(), work2(), work3();
#pragma omp parallel sections
{
#pragma omp section
incr_pair(p, work1(), work2());
#pragma omp section
incr_b(p, work3());
}
}
A.18 지시문에 중첩됨
다음 지시문 중 for
지시문 중첩 예제는 내부 및 외부 for
지시문이 서로 다른 병렬 영역에 바인딩되므로 규격입니다.
#pragma omp parallel default(shared)
{
#pragma omp for
for (i=0; i<n; i++)
{
#pragma omp parallel shared(i, n)
{
#pragma omp for
for (j=0; j<n; j++)
work(i, j);
}
}
}
이전 예제의 다음과 같은 변형도 규격입니다.
#pragma omp parallel default(shared)
{
#pragma omp for
for (i=0; i<n; i++)
work1(i, n);
}
void work1(int i, int n)
{
int j;
#pragma omp parallel default(shared)
{
#pragma omp for
for (j=0; j<n; j++)
work2(i, j);
}
return;
}
A.19 작업 공유 지시문의 잘못된 중첩을 보여 주는 예제
이 섹션의 예제에서는 지시문 중첩 규칙을 보여 줍니다.
다음 예제는 내부 및 외부 for
지시문이 중첩되어 동일한 parallel
지시문에 바인딩되기 때문에 비규격입니다.
void wrong1(int n)
{
#pragma omp parallel default(shared)
{
int i, j;
#pragma omp for
for (i=0; i<n; i++) {
#pragma omp for
for (j=0; j<n; j++)
work(i, j);
}
}
}
이전 예제의 다음 동적 중첩 버전도 비규격입니다.
void wrong2(int n)
{
#pragma omp parallel default(shared)
{
int i;
#pragma omp for
for (i=0; i<n; i++)
work1(i, n);
}
}
void work1(int i, int n)
{
int j;
#pragma omp for
for (j=0; j<n; j++)
work2(i, j);
}
다음 예제는 for
및 single
지시문이 중첩되고 동일한 병렬 영역에 바인딩되기 때문에 비규격입니다.
void wrong3(int n)
{
#pragma omp parallel default(shared)
{
int i;
#pragma omp for
for (i=0; i<n; i++) {
#pragma omp single
work(i);
}
}
}
다음 예제는 for
내부의 barrier
지시문으로 인해 교착 상태가 발생할 수 있으므로 비규격입니다.
void wrong4(int n)
{
#pragma omp parallel default(shared)
{
int i;
#pragma omp for
for (i=0; i<n; i++) {
work1(i);
#pragma omp barrier
work2(i);
}
}
}
다음 예제는 barrier
로 인해 한 번에 하나의 스레드만 중요 섹션에 들어갈 수 있기 때문에 교착 상태가 발생하므로 비규격입니다.
void wrong5()
{
#pragma omp parallel
{
#pragma omp critical
{
work1();
#pragma omp barrier
work2();
}
}
}
다음 예제는 barrier
로 인해 하나의 스레드만 single
섹션을 실행하여 교착 상태가 발생하므로 비규격입니다.
void wrong6()
{
#pragma omp parallel
{
setup();
#pragma omp single
{
work1();
#pragma omp barrier
work2();
}
finish();
}
}
A.20 barrier 지시문 바인딩
지시문 바인딩 규칙은 가장 가까운 바깥쪽 parallel
지시문에 바인딩할 barrier
지시문을 호출합니다. 지시문 바인딩에 대한 자세한 내용은 섹션 2.8을 참조하세요.
다음 예제에서는main에서 sub2로의 호출은 규격이며 이는 barrier
(sub3 내)가 sub2의 병렬 영역에 바인딩하기 때문입니다. main에서 sub1로의 호출은 규격이며 이는 barrier
가 서브루틴 sub2의 병렬 영역에 바인딩하기 때문입니다. main에서 sub3으로의 호출은 규격이며 이는 barrier
가 어떤 병렬 영역에도 바인딩되지 않고 무시되기 때문입니다. 또한 barrier
은 sub1에서 만든 모든 스레드가 아닌, 바깥쪽 병렬 영역에 있는 스레드 팀을 동기화합니다.
int main()
{
sub1(2);
sub2(2);
sub3(2);
}
void sub1(int n)
{
int i;
#pragma omp parallel private(i) shared(n)
{
#pragma omp for
for (i=0; i<n; i++)
sub2(i);
}
}
void sub2(int k)
{
#pragma omp parallel shared(k)
sub3(k);
}
void sub3(int n)
{
work(n);
#pragma omp barrier
work(n);
}
A.21 private 절을 사용하여 변수에 범위 지정
다음 예제의 i
및 j
값은 병렬 영역에서 끝날 때 정의되지 않습니다.
int i, j;
i = 1;
j = 2;
#pragma omp parallel private(i) firstprivate(j)
{
i = 3;
j = j + 2;
}
printf_s("%d %d\n", i, j);
private
절에 대한 자세한 내용은 섹션 2.7.2.1을 참조하세요.
A.22 default(none) 절
다음 예제에서는 default(none)
절의 영향을 받는 변수와 그렇지 않은 변수를 구분합니다.
// openmp_using_clausedefault.c
// compile with: /openmp
#include <stdio.h>
#include <omp.h>
int x, y, z[1000];
#pragma omp threadprivate(x)
void fun(int a) {
const int c = 1;
int i = 0;
#pragma omp parallel default(none) private(a) shared(z)
{
int j = omp_get_num_thread();
//O.K. - j is declared within parallel region
a = z[j]; // O.K. - a is listed in private clause
// - z is listed in shared clause
x = c; // O.K. - x is threadprivate
// - c has const-qualified type
z[i] = y; // C3052 error - cannot reference i or y here
#pragma omp for firstprivate(y)
for (i=0; i<10 ; i++) {
z[i] = y; // O.K. - i is the loop control variable
// - y is listed in firstprivate clause
}
z[i] = y; // Error - cannot reference i or y here
}
}
default
절에 대한 자세한 내용은 섹션 2.7.2.5 를 참조하세요.
A.23 ordered 지시문 예제
ordered
절과 함께 for
이 지정된 여러 개의 순서가 지정된 섹션이 있을 수 있습니다. 첫 번째 예제는 API가 다음 규칙을 지정하기 때문에 비규격입니다.
“for
구문이 포함된 루프 반복은 동일한 순서의 ordered
지시문을 두 번 이상 실행해서는 안 되며, ordered
지시문을 두 번 이상 실행해서는 안 됩니다.”(섹션 2.6.6참조)
이 비규격 예제에서 모든 반복은 순서가 지정된 두 섹션을 실행합니다.
#pragma omp for ordered
for (i=0; i<n; i++)
{
...
#pragma omp ordered
{ ... }
...
#pragma omp ordered
{ ... }
...
}
다음 규격 예제에서는 for
과 함께 순서가 지정된 섹션이 두 개 이상 있는 것을 보여줍니다.
#pragma omp for ordered
for (i=0; i<n; i++)
{
...
if (i <= 10)
{
...
#pragma omp ordered
{ ... }
}
...
(i > 10)
{
...
#pragma omp ordered
{ ... }
}
...
}
A.24 private 절 예제
병렬 영역의 private 절은 영역의 동적 범위가 아니라 영역의 어휘 범위에만 적용됩니다. 따라서 다음 예제에서 루틴 f 내의 for
루프에 for
있는 a 변수의 모든 사용은 a의 프라이빗 복사본을 참조하는 반면, 루틴 g의 사용은 전역 a를 참조합니다.
int a;
void f(int n)
{
a = 0;
#pragma omp parallel for private(a)
for (int i=1; i<n; i++)
{
a = i;
g(i, n);
d(a); // Private copy of "a"
...
}
...
void g(int k, int n)
{
h(k,a); // The global "a", not the private "a" in f
}
A.25 copyprivate 데이터 특성 절 예제
예제 1: copyprivate 절을 사용하여 단일 스레드에서 획득한 값을 다른 스레드의 모든 프라이빗 변수 인스턴스로 직접 브로드캐스트할 수 있습니다.
float x, y;
#pragma omp threadprivate(x, y)
void init( )
{
float a;
float b;
#pragma omp single copyprivate(a,b,x,y)
{
get_values(a,b,x,y);
}
use_values(a, b, x, y);
}
직렬 영역에서 루틴 init 가 호출되는 경우, 해당 동작은 지시문의 존재에 영향을 받지 않습니다. get_values 루틴에 대한 호출이 한 스레드에서 실행된 후에는 모든 스레드에서 a, b, x 및 y로 지정된 프라이빗 개체가 읽은 값으로 정의될 때까지 어떤 스레드도 구문을 벗어나지 않습니다.
예제 2: 이전 예제와 달리, 마스터 스레드와 같이 특정 스레드에서 읽기를 수행해야 한다고 가정합니다. 이 경우 copyprivate
절을 사용하여 브로드캐스트를 직접 수행할 수는 없지만, 임시 공유 개체에 대한 액세스를 제공하는 데 사용할 수 있습니다.
float read_next( )
{
float * tmp;
float return_val;
#pragma omp single copyprivate(tmp)
{
tmp = (float *) malloc(sizeof(float));
}
#pragma omp master
{
get_float( tmp );
}
#pragma omp barrier
return_val = *tmp;
#pragma omp barrier
#pragma omp single
{
free(tmp);
}
return return_val;
}
예제 3: 병렬 영역 내에 필요한 잠금 개체 수를 입력 전에 쉽게 확인할 수 없다고 가정합니다. copyprivate
절을 사용하여 해당 병렬 영역 내에 할당된 공유 잠금 개체에 대한 액세스를 제공할 수 있습니다.
#include <omp.h>
omp_lock_t *new_lock()
{
omp_lock_t *lock_ptr;
#pragma omp single copyprivate(lock_ptr)
{
lock_ptr = (omp_lock_t *) malloc(sizeof(omp_lock_t));
omp_init_lock( lock_ptr );
}
return lock_ptr;
}
A.26 threadprivate 지시문 사용
다음 예제에서는 threadprivate 지시문을 사용하여 각 스레드에 별도의 카운터를 제공하는 방법을 보여 줍니다.
예제 1
int counter = 0;
#pragma omp threadprivate(counter)
int sub()
{
counter++;
return(counter);
}
예제 2
int sub()
{
static int counter = 0;
#pragma omp threadprivate(counter)
counter++;
return(counter);
}
A.27 C99 가변 길이 배열
다음 예제에서는 firstprivate지시문에서 C99 VLA(가변 길이 배열)를 사용하는 방법을 보여 줍니다.
참고 항목
가변 길이 배열은 현재 Visual C++에서 지원하지 않습니다.
void f(int m, int C[m][m])
{
double v1[m];
...
#pragma omp parallel firstprivate(C, v1)
...
}
A.28 num_threads 절
다음 예제에서는 num_threads 절을 보여 줍니다. 병렬 영역은 최대 10개의 스레드로 실행됩니다.
#include <omp.h>
main()
{
omp_set_dynamic(1);
...
#pragma omp parallel num_threads(10)
{
... parallel region ...
}
}
A.29 critical 구문 내의 작업 공유 구문
다음 예제에서는 critical
구문 내에서 작업 공유 구문을 사용하는 방법을 보여 줍니다. 이 예제는 작업 공유 구문과 critical
구문이 동일한 병렬 영역에 바인딩되지 않기 때문에 규격입니다.
void f()
{
int i = 1;
#pragma omp parallel sections
{
#pragma omp section
{
#pragma omp critical (name)
{
#pragma omp parallel
{
#pragma omp single
{
i++;
}
}
}
}
}
}
A.30 재전용화
다음 예제에서는 변수의 재전용화를 보여 줍니다. 프라이빗 변수는 중첩된 지시문에서 private
로 다시 표시할 수 있습니다. 바깥쪽 병렬 영역에서 해당 변수를 공유할 필요는 없습니다.
int i, a;
...
#pragma omp parallel private(a)
{
...
#pragma omp parallel for private(a)
for (i=0; i<10; i++)
{
...
}
}
A.31 스레드로부터 안전한 잠금 함수
다음 C++ 예제에서는 omp_init_lock을 사용하여 병렬 영역에서 잠금 배열을 초기화하는 방법을 보여 줍니다.
// A_13_omp_init_lock.cpp
// compile with: /openmp
#include <omp.h>
omp_lock_t *new_locks() {
int i;
omp_lock_t *lock = new omp_lock_t[1000];
#pragma omp parallel for private(i)
for (i = 0 ; i < 1000 ; i++)
omp_init_lock(&lock[i]);
return lock;
}
int main () {}