병렬 컴퓨터에서 작업을 하다 보면, 별다른 이유없이 프로그램이 실행되지 않으며 아래와 같은 에러 메시지를 출력할 때가 있다.
p4_error: OOPS: semop lock failed: -1
대개의 경우, 이는 더 이상의 가용 세마포어 (semaphore, 깃발 신호)가 남아 있지 않아서이다. 이에 대한 해결책을 제시하기에 앞서, 우선 세마포어가 무엇인지부터 간략하게 알아보자.
세마포어 (semaphore) 란?
세마포어에 대해 좀 더 자세히 알고 싶다면 Vikram Shukla 가 쓴 "Semaphores in Linux" 란 웹문서를 추천한다.
복수의 프로세스 (process) 들이 하나의 또는 제한된 공동 자원 (common resources, or shared resources)에 접속을 할 때, 동시 접속을 방지하는 것에 관여하는 메모리 변수를 지칭한다. 메모리 변수라는 점에서 일반 프로그램 변수와 비슷하나, 차이점은 프로그램 변수는 그 프로그램 안에서만 다루어지는데 비하여 semaphore 데이타는 다른 프로세스들에 의해서도 사용된다는 점이다. (출처: The Linux Tutorial)
[binary semaphore 의 예]
예를 들어, 하나의 데이타 파일에 접속할 수 있는 프로세스들이 여러 개 있는 상황을 가정하자. 한 프로세스가 파일을 편집하고 있는 상황에서 다른 프로세스의 접속을 허용하면, 데이터 파일이 뒤죽박죽되기 마련이다. 이를 막기 위해서, semaphore 의 값이 on (또는 참값) 이면 접근을 허용하고 그 반대의 경우는 불허하게 정한다. 처음으로 접근하는 프로세스가 semaphore 의 값을 off (또는 거짓값) 으로 바꾸고, 파일 작업이 끝나면 semaphore 의 값을 원래대로 돌린다. 다음에 오는 프로세스들은 이 값이 거짓이면 참이 될 때가지 기다리게 된다. 비유를 하자면 공용 화장실이 하나 밖에 없는데, 사람들이 줄서서 기다리는 상황과 비슷하다. 한 명이 들어가서 문을 잠구면(locked), 나머지는 문이 열릴(unlocked) 때까지 기다리는 수 밖에 없다. (Toilet example)
[counting semaphore 의 예]
다른 예로서 식당의 비유 (출처: wiki)를 드는데, 이 비유에서 식당의 자리는 공동 자원에, 찾아오는 손님은 프로세스에 해당한다. 자리의 수는 제한되어 있으므로 찾아오는 손님마다 다 앉힐 수는 없는 노릇이다. 이 경우 식당에 안내하는 사람이 있어서, 자리가 다 차면 손님을 기다리게 하고 자리가 나면 우선 순위의 손님부터 받아들이는 등의 조정을 할 것이다. 이 안내자의 역할이 semaphore 에 해당하는 것이다.
세마포어에 대해 좀 더 자세히 알고 싶다면 Vikram Shukla 가 쓴 "Semaphores in Linux" 란 웹문서를 추천한다.
이 semaphore 를 포함한 IPC (Inter-Process Communication)들의 크기나 개수는 시스템이 정한 제한이 있다. (출처:Vinay's Tech Stuff)
병렬 프로그램들이 비정상적으로 종료한 경우, semaphore가 여전히 그 프로그램에 의해서 사용되고 있는 것으로 남아서 제한된 가용 semaphore을 잠식한다. semop locked failed error 는 이러한 상황에서 연유한다. 그러므로, 사용되지 않는 semaphore array를 지우면 문제가 해결된다. 먼저, 아래의 명령어로 어떤 semaphore가 남아 있는지 알아 보자.
[user@linuxcluster ~]$ ipcs -s
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 10485790 user 777 1
0x00000000 10518559 user 777 1
0x00000000 10551328 user 777 1
0x00000000 10584097 user 777 1
0x00000000 10616866 user 777 1
0x00000000 10649635 user 777 1
0x00000000 10682404 user 777 1
0x00000000 10715173 user 777 1
0x00000000 10747942 user 777 1
0x00000000 10780711 user 777 1
0x00000000 10813480 user 777 1
0x00000000 10846249 user 777 1
0x00000000 10879018 user 777 1
0x00000000 10911787 user 777 1
0x00000000 10944556 user 777 1
0x00000000 10977325 user 777 1
0x00000000 11010094 user 777 1
0x00000000 11042863 user 777 1
0x00000000 11075632 user 777 1
0x00000000 11108401 user 777 1
0x00000000 11141170 user 777 1
0x00000000 11173939 user 777 1
0x00000000 11206708 user 777 1
0x00000000 11239477 user 777 1
0x00000000 11272246 user 777 1
0x00000000 11305015 user 777 1
0x00000000 11337784 user 777 1
------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 10485790 user 777 1
0x00000000 10518559 user 777 1
0x00000000 10551328 user 777 1
0x00000000 10584097 user 777 1
0x00000000 10616866 user 777 1
0x00000000 10649635 user 777 1
0x00000000 10682404 user 777 1
0x00000000 10715173 user 777 1
0x00000000 10747942 user 777 1
0x00000000 10780711 user 777 1
0x00000000 10813480 user 777 1
0x00000000 10846249 user 777 1
0x00000000 10879018 user 777 1
0x00000000 10911787 user 777 1
0x00000000 10944556 user 777 1
0x00000000 10977325 user 777 1
0x00000000 11010094 user 777 1
0x00000000 11042863 user 777 1
0x00000000 11075632 user 777 1
0x00000000 11108401 user 777 1
0x00000000 11141170 user 777 1
0x00000000 11173939 user 777 1
0x00000000 11206708 user 777 1
0x00000000 11239477 user 777 1
0x00000000 11272246 user 777 1
0x00000000 11305015 user 777 1
0x00000000 11337784 user 777 1
이는 header node에 남아 있는 semaphore array만 보여준다. 모든 node 에 남아 있는 semaphore array를 볼려면 cluster-fork 라는 명령어를 이용한다. 이 때, node의 숫자에 따라 출력문이 길 수도 있으므로 파일( semaphore-list.txt) 로 받는게 더 좋다.
[user@linuxcluster ~]$ cluster-fork ipcs -s > semaphore-list.txt
확인된 semaphore array 의 소유자 (owner)가 자신이면 ipcrm -s <SEMID> 란 명령어로 지울 수 있다. 예를 들어, 이런 식이다.
[user@linuxcluster ~]$ ipcrm -s 11337784
위 명령어는 오직 지정된 ID의 semaphore array만 삭제한다. 모든 sem array를 지우고 싶다면, cleanipcs란 명령어를 이용한다. cleanipcs는 보통 관리자 권한에서만 실행되므로 일반 사용자는 실행할 수 없다. 관리자에게 부탁해서 자신의 로컬 디렉토리에 복사해서 사용한다. (본인은 ~/bin 디렉토리에 저장해서 사용한다.) 이 경우, 타인에게 권한이 있는 sem array는 삭제할 수 없다. 타인의 sem array는 해당 사용자에게 지워줄 것을 부탁해야 한다. 모든 node에서 자신의 sem array를 지울려면 다음과 같이 cluster-fork를 이용하여 cleanipcs를 실행한다.
[user@linuxcluster ~]$ cluster-fork ~/bin/cleanipcs
만약에 cleanipcs를 구할 수 없으면, 차선책으로 다음의 쉘 스크립트 (shell script) 파일을 만들어서 실행한다.
[user@linuxcluster ~]$ cat > rmsem.i686.sh
#!/bin/sh
ipcs | cut -f 2 -d ' ' | xargs ipcrm shm
ipcs | cut -f 2 -d ' ' | xargs ipcrm sem
ipcs
ctrl + D
[user@linuxcluster ~]$ chmod 744 rmsem.i686.sh
[user@linuxcluster ~]$ cluster-fork rmsem.i686.sh
#!/bin/sh
ipcs | cut -f 2 -d ' ' | xargs ipcrm shm
ipcs | cut -f 2 -d ' ' | xargs ipcrm sem
ipcs
ctrl + D
[user@linuxcluster ~]$ chmod 744 rmsem.i686.sh
[user@linuxcluster ~]$ cluster-fork rmsem.i686.sh
이제 좀비(zombie) semaphore array를 깨끗하게 지웠으니, 프로그램이 문제없이 실행될 것이다.