매우 대중적인 Boost 라이브러리를 사용하는 동시 프로그래밍은 굉장히 재미있다. Boost는 동시 프로그래밍 공간 내에 몇 가지 라이브러리를 보유한다 — 공유 메모리, 메모리 맵핑된 I/O 및 메시지 큐를 위한 Interprocess 라이브러리(IPC), 휴대용 멀티 스레딩을 위한 Thread 라이브러리, 분산 컴퓨팅에 사용이 발견되는 메시지 전달을 위한 Message Passing Interface(MPI) 라이브러리 및 소켓과 다른 낮은 레벨 함수를 사용하여 휴대용 네트워킹을 위한 Asio 라이브러리 등이다. 이 기사는 제공하는 일부 기능과 함께 IPC 및 MPI 라이브러리를 소개한다.
이 기사에서 독자는 공유 메모리 오브젝트, 메시지 큐 및 동기화된 파일 잠금을 구현하기 위해 Boost IPC 라이브러리를 사용하는 방법을 학습한다. Boost MPI 라이브러리를 사용하면 환경과 커뮤니케이터 클래스에 대해 학습하고 분산된 통신을 어떻게 달성할 수 있는지에 대해 학습한다.
참고: 이 기사의 코드는
gcc-4.3.4 및 boost-1.45
패키지를 사용하여 테스트되었다.
Boost Interprocess는 헤더 전용 라이브러리이므로 독자가 해야 할 일은 소스에 적절한 헤더를 포함시키고
컴파일러가 include 경로를 인식하도록 하는 것이다. 이는 보유하기에 훌륭한 기능이다. 즉,
Boost 소스(링크는 참고자료 참조)를 다운로드하기만 하면 시작할 준비가 된 것이다. 예를 들어,
코드에서 공유 메모리를 사용하기 위해 목록 1과 같이 include를 사용한다.
목록 1. Boost IPC 라이브러리는 헤더 전용 문제이다
#include <boost/interprocess/shared_memory_object.hpp> using namespace boost::interprocess; //… your sources follow … |
컴파일러에 정보를 전달할 때, 독자는 리더가 적절하게 설치당
include 경로를 수정하도록 요청한다.
그 다음에 코드를 컴파일한다.
bash-4.1$ g++ ipc1.cpp –I../boost_1_45_0 |
관례적인 "Hello World!" 프로그램으로 시작하자. 두 가지 프로세스가 있는데, 전자는 "Hello World!" 문자열을 공유 메모리에 쓰는 것이고, 후자는 그 문자열을 읽고 표시하는 것이다. 목록 2와 같이 공유 메모리 오브젝트를 작성한다.
목록 2. 공유 메모리 오브젝트 작성하기
#include <boost/interprocess/shared_memory_object.hpp>
int main(int argc, char* argv[ ])
{
using namespace using boost::interprocess;
try {
// creating our first shared memory object.
shared_memory_object sharedmem1 (create_only, "Hello", read_write);
// setting the size of the shared memory
sharedmem1.truncate (256);
// … more code follows
} catch (interprocess_exception& e) {
// .. . clean up
}
}
|
sharedmem1 오브젝트는
shared_memory_object 유형이고(Boost 헤더로 선언되고 정의됨)
생성자에서 세 가지 인수를 취한다.
- 첫 번째 인수—
create_only—는 이 공유 메모리 오브젝트가 작성되고 아직 작성되지 않았음을 의미한다. 동일한 이름의 공유 오브젝트가 이미 존재하면, 예외가 발생할 것이다. 이미 작성된 공유 메모리에 대한 액세스 권한을 가지려는 프로세스의 경우 첫 번째 인수는open_only이어야 한다. - 두 번째 인수—
Hello—는 공유 메모리 영역의 이름이다. 이 공유 메모리에 액세스하는 또 다른 프로세스는 액세스의 이 이름을 사용하게 될 것이다. - 세 번째 인수—
read_write—는 공유 메모리 오브젝트의 액세스 지정자이다. 이 프로세스가 공유 메모리 오브젝트의 컨텐츠를 수정하기 때문에 독자는read_write를 사용한다. 이 공유 메모리로부터만 읽는 프로세스는 액세스를 위해read_only지정자를 사용한다.
truncate 메소드는 바이트로 공유 메모리의 크기를 설정한다. 코드는 이상적으로 try-catch
블록으로 랩핑되어야 한다. 예를 들어, 공유 메모리 오브젝트가 작성될 수 없으면,
boost::interprocess_exception 유형의 예외가 발생한다.
공유 메모리 오브젝트를 사용하기 위한 프로세스의 경우 해당 프로세스는 주소 공간에 오브젝트를 맵핑해야
한다. 맵핑은 헤더 mapped_region.hpp에서 선언되고 정의되는 mapped_region 클래스를
사용하여 수행된다. mapped_region 사용의 또 다른 이점은 공유 메모리 오브젝트로의
전체 및 부분적 액세스가 가능하다는 점이다. 목록 3은
mapped_region을 사용하는 방법을 보여준다.
목록 3. 공유 메모리 오브젝트에 액세스하기 위해 mapped_region 사용하기
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
int main(int argc, char* argv[ ])
{
using namespace boost::interprocess;
try {
// creating our first shared memory object.
shared_memory_object sharedmem1 (create_only, "Hello", read_write);
// setting the size of the shared memory
sharedmem1.truncate (256);
// map the shared memory to current process
mapped_region mmap (sharedmem1, 256);
// access the mapped region using get_address
std::strcpy(static_cast<char* >(region.get_address()), "Hello World!\n");
} catch (interprocess_exception& e) {
// .. . clean up
}
}
|
정말 이제 다 되었다. 독자는 mapped_region 오브젝트를 작성했고
get_address 메소드를 사용하여 액세스했다.
get_address가 void*를 리턴하기 때문에
static_cast가 수행되었다.
기본 메모리를 종료할 때 공유 메모리는 어떻게 되는가?
공유 메모리는 프로세스를 종료할 때 삭제되지 않는다. 공유 메모리를 삭제하려면
shared_memory_object::remove를 호출해야 한다. 프로세스 2에 대한 액세스 메커니즘은
매우 간단하다. 목록 4는 이 점을 입증한다.
목록 4. 두 번째 프로세스에서 공유 메모리 오브젝트 액세스하기
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <cstring>
#include <cstdlib>
#include <iostream>
int main(int argc, char *argv[ ])
{
using namespace boost::interprocess;
try {
// opening an existing shared memory object
shared_memory_object sharedmem2 (open_only, "Hello", read_only);
// map shared memory object in current address space
mapped_region mmap (sharedmem2, read_only);
// need to type-cast since get_address returns void*
char *str1 = static_cast<char*> (mmap.get_address());
std::cout << str1 << std::endl;
} catch (interprocess_exception& e) {
std::cout << e.what( ) << std::endl;
}
return 0;
}
|
목록 4에서 open_only 및
read_only 속성을 사용하여 공유 메모리 오브젝트를 작성한다. 공유 메모리 오브젝트를
발견할 수 없으면 예외가 발생한다. 이제
목록 3과 목록 4에서 코드를 빌드하고 실행한다. 터미널에서
"Hello World!"가 표시되어야 한다.
다음으로 std::cout 바로 뒤에
두 번째 프로세스(목록 4)의 코드에 있는 다음 행을 추가한 후 코드를 다시 빌드한다.
// std::cout code here
shared_memory_object::remove("Hello");
// } catch(interprocess_exception& e) {
|
코드를 두 번 연속으로 실행한다. 두 번째 실행이 출력하는 "No such file or directory" 행을 통해 공유 메모리가 삭제되었음을 확인한다.
이제 프로세스 간 통신의 또 다른 대중적 메커니즘인 메시지 큐를 살펴보자. 각 통신 프로세스는 큐에 메시지를 추가하고 큐에서부터 메시지를 읽을 수 있다. 메시지 큐는 다음 특성이 나타난다.
- 이는 이름이 있고 주어진 이름을 사용하여 액세스하는 프로세스가 있다.
- 큐 작성 중 사용자는 최대 큐 길이 및 개별 메시지의 최대 크기를 지정해야 한다.
- 큐는 지속적이므로 큐를 작성한 해당 프로세스를 종료하더라도 메모리에 남는다. 큐는
boost::interprocess::message_queue::remove로 명시적 호출을 사용하여 제거해야 한다.
목록 5는 프로세스가 20개 정수의 메시지 큐를 작성한 코드 스니펫을 보여준다.
목록 5. 20개 정수의 메시지 큐 작성하기
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
int main(int argc, char* argv[ ])
{
using namespace boost::interprocess;
try {
// creating a message queue
message_queue mq (create_only, // only create
"mq", // name
20, //max message count
sizeof(int) //max message size
);
// … more code follows
} catch (interprocess_exception& e) {
std::cout << e.what( ) << std::endl;
}
}
|
create_only 속성이
message_queue에 대해 생성자에 전달되었음을 참고하자. 공유 메모리 오브젝트에 대한 경우와 마찬가지로,
읽기 전용으로 열린 메시지 큐는 생성자에 전달된
open_only 속성을 보유할 것이다.
전송하는 측에서 데이터를 추가하기 위해 큐의 send 메소드를 사용한다. send 메소드 시그니처는
다음 세 가지 입력이 있다. 즉, 이는 원시 데이터로 포인터(void*), 데이터의 크기 및 우선순위이다. 여기에서는 모든 숫자를 동일한 우선순위로
전송한다. 목록 6은 코드를 보여준다.
목록 6. 큐로 메시지 전송하기
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
int main(int argc, char* argv[ ])
{
using namespace boost::interprocess;
try {
// creating a message queue
message_queue mq (create_only, // only create
"mq", // name
20, //max message count
sizeof(int) //max message size
);
// now send the messages to the queue
for (int i=0; i<20; ++i)
mq.send(&i, sizeof(int), 0); // the 3rd argument is the priority
} catch (interprocess_exception& e) {
std::cout << e.what( ) << std::endl;
}
}
|
수신하는 측에서 큐는 open_only 속성에서 취한다. 개별 메시지는 message_queue 클래스의
receive 메소드를 호출하여 큐로부터 얻게 된다. 목록 7은
receive 메소드 시그니처를 보여준다.
t목록 7. message_queue::receive에 대한 메소드 시그니처
void receive (void *buffer,
std::size_t buffer_size,
std::size_t &recvd_size,
unsigned int &priority
);
|
이를 약간 해석해보자. 첫 번째 인수는 큐로부터 수신된 데이터가 저장될 곳이다. 두 번째 인수는 수신된 데이터의 예상된 크기이다. 세 번째 인수는 수신된 데이터의 실제 크기이며, 네 번째 인수는 수신된 메시지의 우선순위이다. 분명히 두 번째와 세 번째 인수가 프로그램 실행 과정 동안 동일하지 않은 것으로 밝혀지면 오류이다. 목록 8은 수신자 프로세스에 코드를 제공한다.
목록 8. 메시지 큐로부터 메시지 수신하기
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
int main(int argc, char* argv[ ])
{
using namespace boost::interprocess;
try {
// opening the message queue whose name is mq
message_queue mq (open_only, // only open
"mq" // name
);
size_t recvd_size;
unsigned int priority;
// now send the messages to the queue
for (int i=0; i<20; ++i) {
int buffer;
mq.receive ((void*) &buffer, sizeof(int), recvd_size, priority);
if (recvd_size != sizeof(int))
; // do the error handling
std::cout << buffer << " " << recvd_size << " " << priority;
}
} catch (interprocess_exception& e) {
std::cout << e.what( ) << std::endl;
}
}
|
이는 매우 간단했다. 여전히 메모리에서부터 메시지 큐를 제거하지 않았음을 참고하자. 즉, 공유 메모리 오브젝트와 마찬가지로, 이 큐는 지속적이다. 큐를 제거하기 위해 큐를 사용하여 수행할 때마다 다음 행을 추가한다.
message_queue::remove("mq"); // remove the queue using its name
|
전송하는 측에서 목록 9와 같이 수정한다. 수신자 코드는 변경할 필요가 없다.
목록 9. 메시지의 우선순위 변경하기
message_queue::remove("mq"); // remove the old queue
message_queue mq (…); // create as before
for (int i=0; i<20; ++i)
mq.send(&i, sizeof(int), i%2); // the 3rd argument is the priority
// … rest as usual
|
코드를 다시 실행하면 바로 목록 10에 제공된 출력이 표시되어야 한다.
목록 10. 수신 프로세스에서 확인된 출력
1 4 1 3 4 1 5 4 1 7 4 1 9 4 1 11 4 1 13 4 1 15 4 1 17 4 1 19 4 1 0 4 0 2 4 0 4 4 0 6 4 0 8 4 0 10 4 0 12 4 0 14 4 0 16 4 0 18 4 0 |
더 높은 우선순위 메시지는 목록 10에서 확인한 대로 두 번째 프로세스에 제거될 수 있을 것이다.
공유 메모리 및 메시지 큐는 훌륭하지만, 파일 I/O는 프로세스들이 서로 통신하기 위해 사용하는 중요한 도구이기도 하다. 통신하기 위해 동시 프로세스로
사용한 파일 액세스 동기화는 간편한 태스크가 아니지만, Boost IPC 라이브러리로부터 파일 잠금 기능은 수행하기에 더 간편하다. 추가로 설명하기 전에
file_lock 오브젝트가 어떻게 작동하는지 이해하기 위해 목록 11을 살펴보자.
목록 11. 파일 액세스 동기화를 위해 file_lock 오브젝트 사용하기
#include <fstream>
#include <iostream>
#include <boost/interprocess/sync/file_lock.hpp>
#include <cstdlib>
int main()
{
using namespace boost::interprocess;
std::string fileName("test");
std::fstream file;
file.open(fileName.c_str(), std::ios::out | std::ios::binary |
std::ios::trunc);
if (!file.is_open() || file.bad())
{
std::cout << "Open failed" << std::endl;
exit(-1);
}
try {
file_lock f_lock(fileName.c_str());
f_lock.lock();
std::cout << "Locked in Process 1" << std::endl;
file.write("Process 1", 9);
file.flush();
f_lock.unlock();
std::cout << "Unlocked from Process 1" << std::endl;
} catch (interprocess_exception& e) {
std::cout << e.what( ) << std::endl;
}
file.close();
return 0;
}
|
이 코드는 먼저 파일을 연 다음에 file_lock을 사용하여 잠근다. 쓰기를 완료하면 바로 파일 버퍼를 흘려 버리고
파일을 잠금 해제한다. 독자는 파일로 독점 액세스를 확보하기 위해
lock 메소드를 사용한다. 이미 잠금을 호출하고 파일에 쓰기를 시도하는 또 다른 프로세스가 있는 경우,
첫 번째 프로세스가 unlock을 사용하여 자발적으로 포기할 때까지 두 번째 프로세스는 대기한다. file_lock
클래스의 생성자는 잠기는 파일의 이름을 승인한다.
lock이 호출되기 전에 파일을 여는 것이 중요하다. 그렇지 않으면 예외가 발생할 것이다.
이제 목록 11의 코드를 복사하여 변경하자. 구체적으로 말하면, 이를 잠금을 요청하는 두 번째 프로세스로 만든다. 목록 12는 관련된 변경을 보여준다.
목록 12. 파일에 액세스를 시도하는 두 번째 프로세스용 코드
// .. as in Listing 11
file_lock f_lock(fileName.c_str());
f_lock.lock();
std::cout << "Locked in Process 2" << std::endl;
system("sleep 4");
file.write("Process 2", 9);
file.flush();
f_lock.unlock();
std::cout << "Unlocked from Process 2" << std::endl;
// file.close();
|
이제 이러한 두 가지 프로세스가 동시에 실행되는 경우, 첫 번째 프로세스가
해당 시간의 file_lock 50퍼센트를 확보하기 전에 4초를 대기할 것을 예상하며,
다른 것도 모두 마찬가지이다.
file_lock을 사용할 때 주의해야 할 몇 가지 사항이 있다. 여기에서는
프로세스를 강조하여 프로세스 간 통신에 대해 논의하고 있다.
이는 독자가 동일한 프로세스의 스레드로 데이터 액세스를 동기화하기 위해 file_lock을 사용한다고 가정하지 않음을 의미한다. POSIX 호환 시스템에서
파일 처리는 프로세스이고 스레드 속성이 아니다. 파일 잠금 사용과 관련한 몇 가지 가이드라인은 다음과 같다.
- 매 프로세스의 파일당 하나의
file_lock오브젝트를 사용한다. - 파일을 잠금 처리하고 잠금 해제하기 위해 동일한 스레드를 사용한다.
C의flush라이브러리 루틴 또는flush메소드(C++ fstream을 선호하는 경우)를 호출하여 파일을 잠금 해제하기 전에 라이터 프로세스에서 데이터를 흘려 버린다.
프로그램 실행 도중에 일부 예외가 발생하고 파일이 잠금 해제되지 않을 수 있다. 이러한 일은 원하지 않는 프로그램 작동을
야기할 수 있다. 이러한 상황을 방지하기 위해 boost/interprocess/sync/scoped_lock.hpp에서 정의된 scoped_lock에서 file_lock
오브젝트를 랩핑하는 것을 고려한다. scoped_lock을 사용하면 파일을 명시적으로 잠그거나 잠금 해제할 필요가 없다.
즉, 잠금은 생성자 내에서 발생하며, 잠금 해제는 범위를 벗어날 때마다 자동으로 나타난다. 목록 13은 범위 지정된 잠금을 사용하도록
목록 11의 수정을 보여준다.
목록 13. file_lock으로 scoped_lock 사용하기
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
//… code as in Listing 11
file_lock f_lock(fileName.c_str());
scoped_lock<file_lock> s_lock(f_lock); // internally calls f_lock.lock( );
// No need to call explicit lock anymore
std::cout << "Locked in Process 1" << std::endl;
file.write("Process 1", 9);
// … code as in Listing 11
|
참고: Resource Acquisition Is Initialization (RAII) 프로그래밍 관용구의 추가 정보관련 링크는 참고자료 를 참조한다.
Boost MPI를 알아보기 전에 독자가 아직 Message Passing Interface에 익숙하지 않다면
참고자료 섹션에 제공되는 MPI 섹션관련 링크를 간단히 확인해야 한다. MPI는
메시지를 전달하여 서로 통신하는 프로세스의 모델에서 작업하는 사용하기 간편한 표준이다.
소켓이나 다른 레벨 통신 기초 요소를 사용하지 않아도 된다. 즉, MPI 백엔드가 모든 어려운 작업을 관리한다. 그렇다면 Boost MPI는 어디에 적합한가? Boost MPI의 창시자는
더 높은 추상화 레벨과 MPI_Init 및 MPI_Bcast 등의 MPI 제공된 API의 위에 제작된 간단한 루틴 세트를 제공했다.
Boost MPI는 사용자가 다운로드하고 빌드하며 작업을 준비한다는 관점에서 볼 때 독립형 라이브러리가 아니다. 그 대신에, 독자는 MPICH 또는 Open MPI와 같은 어느 MPI 구현 방식이나 설치하고 Boost Serialization 라이브러리를 빌드해야 한다. Boost MPI를 빌드하는 방법에 대한 자세한 정보는 참고자료를 참조하자. 대개 다음 명령을 사용하여 Boost MPI를 빌드할 것이다.
bash-4.1$ bjam –with-mpi |
Windows® 사용자는 BoostPro에서 MPI용으로 사전 빌드된 라이브러리를 다운로드할 수 있다(참고자료 참조). 라이브러리는 Microsoft® HPC Pack 2008 및 2008 R2(참고자료 참조)와 호환 가능하고 Windows XP 서비스 팩 3 이상 클라이언트 운영 체제에서 작동한다.
Boost MPI 라이브러리의
environment 클래스와
communicator 클래스는 반드시 알아야 하는 두 가지 기본 클래스이다. 전자는 분산 환경 초기화를 담당하고, 후자는
프로세스 간 통신에 사용된다. 여기에서는 분산된 컴퓨팅에 대해 논의 중이므로
네 가지 프로세스 모두가 터미널에 "Hello World"를 출력하도록 설정한다. 목록 14는 코드를 보여준다.
목록 14. Boost MPI를 사용하는 Hello World
#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::mpi::environment env(argc, argv);
boost::mpi::communicator world;
std::cout << argc << std::endl;
std::cout << argv[0] << std::endl;
std::cout << "Hello World! from process " << world.rank() << std::endl;
return 0;
}
|
이제 Boost MPI 및 Serialization 라이브러리로의 적절한 링크를 통해 목록 14에서 코드를 빌드하자. 쉘 프롬프트에서 실행 파일을 실행한다. "Hello World! from process 0"이
표시되어야 한다. 그 다음으로 MPI 디스패처 도구를 사용하고—예를 들어,
Open MPI 사용자용 mpirun 및 Microsoft HPC Pack 2008용
mpiexec— 다음으로 실행 파일을 실행한다.
mpirun –np 4 <executable name> OR mpiexec –n 4 <executable name> |
이제 실행 파일 이름을 mympi1로 목록 15와 같이 표시되어야 한다.
목록 15. MPI 코드를 실행하여 나온 결과
1 mympi1 Hello, World! from process 3 1 mympi1 1 mympi1 Hello, World! from process 1 Hello, World! from process 2 1 mympi1 Hello, World! from process 0 |
이제 다 되었다. MPI 프레임워크 내에서 네 개의 동일한 프로세스 사본이 작성되었다. MPI 환경 내에서 각 프로세스는 고유 ID가 있으며, 이는
communicator 오브젝트로 결정된다. 이제 프로세스 사이에 통신을 시도해보자. send 및 receive
함수 호출을 사용하여 하나의 프로세스가 다른 프로세스와 통신하도록 하자. 메시지를 전송하는 프로세스를 마스터 프로세스라고 하고
메시지를 수신하는 프로세스를 워커 프로세스라고 한다. 소스 코드는
world 오브젝트가 제공하는 등급을 사용하여 결정된 기능을 통해 마스터와 수신자 둘 다를 위해 동일하다(목록 16 참조).
목록 16. 서로 통신하는 프로세스 0, 1 및 2에 대한 코드
#include <boost/mpi.hpp>
#include <iostream>
int main(int argc, char* argv[])
{
boost::mpi::environment env(argc, argv);
boost::mpi::communicator world;
if (world.rank() == 0) {
world.send(1, 9, 32);
world.send(2, 9, 33);
} else {
int data;
world.recv(0, 9, data);
std::cout << "In process " << world.rank( ) << "with data " << data
<< std::endl;
}
return 0;
}
|
send 함수로 시작하자. 첫 번째 ID는 수신자 프로세스의 ID이고 두 번째 ID는 메시지 데이터의 ID이고
세 번째 ID는 실제 데이터의 ID이다. 왜 메시지 태그가 필요한가? 수신자 프로세스는 실행 도중에 어느 시점에 특정 태그가 있는 메시지를 처리하려 할 수 있으므로
작업을 수행하는 이러한 스킴이 도움이 된다. 프로세스 1과 2의 경우, recv
함수가 차단하고 있다. 이는 프로그램이 프로세스 0에서부터 태그 ID 9로 메시지를 수신할 때까지 대기할 것임을 의미한다.
메시지를 수신할 때, 정보가 데이터에 저장된다. 여기에 코드를 실행할 때 출력이 나와있다.
In process 1 with data 32 In process 2 with data 33 |
그러면 수신자 측에 world.recv(0, 1, data);와 같은 것이 있다면 어떻게 되는가? 코드는 정지하지만, 현실에서 수신자 프로세스는
절대 도착하지 않을 태그가 있는 메시지에 대해 대기하는 중이다.
이 기사는 유용한 두 가지 라이브러리가 제공하는 기능을 수박 겉핥기 식으로만 살펴보았다. 이러한 라이브러리가 제공하는 다른 기능은 IPC의 메모리 맵핑된 I/O 및 MPI의 브로드캐스트 기능이 포함된다. 가용성의 관점에서 보면 IPC는 사용하기에 간편하다. 하지만, MPI 라이브러리가 네이티브 MPI 구현에 의존적이라는 부분과 사전 빌드된 Boost MPI 및 Serialization 라이브러리와 네이티브 MPI의 분리 가능 여부는 여전히 문제가 된다. 그럼에도 불구하고 소스에서부터 MPI 구현 방식과 Boost에 대해 빌드를 작성하는 것은 노력할 만한 가치가 있다.
교육
-
interprocess
communication에 대해 자세히 배워보자.
-
Boost MPI 빌드 방법에 대해 살펴보자.
-
모든
mpirun옵션을 살펴보자. -
RAII idiom에 대해 자세히 살펴보자.
-
Message Passing Interface
표준을 읽어보자.
-
Microsoft
HPC Pack 2008/R2 SDK에 대해 자세히 살펴보자.
-
AIX와 UNIX developerWorks 영역: AIX와 UNIX 영역에서는 AIX 시스템 관리와 UNIX 스킬 확장의 모든 측면과 관련된 풍부한 정보를 제공한다.
-
AIX와 UNIX 입문
AIX와 UNIX 입문 페이지에서 자세한 정보를 볼 수 있다.
-
기술 서점: 다양한 기술 주제와 관련된 서적을 살펴볼 수 있다.
제품 및 기술 얻기
-
Boost
Thread 라이브러리에 대해 자세히 알아보고 다운로드하자.
-
Boost MPI 라이브러리에 대해 자세히 알아보고 다운로드하자.
-
BoostPro에서 사전 빌드된 MPI 라이브러리를 다운로드하자.
-
Boost
IPC 라이브러리를 다운로드하자.
-
MPICH2
다운로드 사이트를 확인하자.
-
Open MPI v1.4
다운로드 사이트를 확인하자.
토론
-
Twitter의 developerWorks 페이지를 팔로우하자.
-
developerWorks 블로그: 블로그를
읽어 보고 developerWorks community에 참여하자.
-
다음과 같은 AIX 및 UNIX 포럼에 참여하자.
- AIX 5L—기술 포럼
- 개발자용 AIX 포럼
- Cluster Systems Management
- IBM Support Assistant
- Performance Tools—기술적
- 기타 AIX 및 UNIX 포럼