4일째 풀고 있는 공유메모리 관련 질문입니다.
아 오랜시간 삽질을 하고나니 도저히 모르겠습니다.
자력으로 어찌해볼수가 없군요. (어려운 문제는 아닐꺼에요.. ;;)
봉착한 문제 : 공유메모리를 접근하는 프로세스에서 read는 되는데 해당 메모리로 write가 안됩니다.
// 프로그램 A, B는 아래와 같은 구조체를 공유메모리로 공유합니다.
typedef struct _linkNode
{
pcb* pcbPtr;
int ioBegin;
struct _linkNode *next;
}linkNode;
// 프로그램 A에서는 위의 구조체를 공유하기 위해 특정 함수 내에서
// 아래의 코드를 실행합니다.
p->pid = craft(); // craft : 프로세스를 생성하고 pid를 리턴하는 함수.
shmId = shmget( (key_t)p->pid, sizeof(linkNode), 0666|IPC_CREAT );
if (shmId == -1)
{
perror("shmget failed : ");
exit(0);
}
sharedMem = shmat(shmId, (void*)0, 0);
if ( sharedMem == (void *)-1 )
{
perror("shmat failed : ");
exit(0);
}
newNode = (linkNode*) sharedMem;
*newNode = *cur;
newNode->ioBegin = -1;
// 그리고는 새로 생긴 newNode가 가리키는 새로 생긴 메모리를 링크드 리스트에 연결시킵니다. (여기서 가정은 shmget을 통해 확보된 메모리 영역은 heap영역과 같이 프로그램 끝날 때 까지 없어지지 않는다는 가정입니다. 맞겠지요?? )
// 이제는 ioBegin을 1로 세팅한후 ioBegin이 프로그램 B에 의해 바뀔 때 까지 계속 기다립니다. 아래에서 cur은 linkNode* 형의 변수입니다. 생성된 newNode중에 한 개를 가리키고 있구요.
cur->ioBegin = 1;
printf("[K] io start : %d", p->pid);
while ( cur->ioBegin == 1 )
{
usleep(1);
}
// 이제는 프로그램 B로 가보면..
// 아래와 같이 공유메모리를 접근합니다. 키값으로 쓴 myPid는 위의 프로그램 A에서 쓴 것과 같습니다.
shmId = shmget( (key_t)myPid, sizeof(linkNode), 0 );
if (shmId == -1)
{
printf("[USER PROCESS %d]shmget failed : ", myPid);
exit(0);
}
sharedMem = shmat(shmId, (void*)0, 0666|IPC_CREAT);
if ( sharedMem == (void *)-1 )
{
printf("[USER PROCESS %d]shmat failed : ", myPid);
exit(0);
}
sharedLinkNode = (linkNode*) sharedMem;
// 위의 프로그램 A에서 ioBegin을 1로 세팅해놓고 계속 busy waiting을 하고 있었는데, 그것을 깨기 위해 ioBegin변수가 1이라면 100으로 세팅하도록 합니다. 이부분에서 문제가 생기는데요 ioBegin변수가 1이어서 while문안의 문장이 실행되면 공유된 ioBegin변수가 응당 100으로 바뀌어야 할 진데 바뀌지 않습니다. 프로그램 A에서 ioBegin변수를 찍어보면 계속 1만 나옵니다;;; 왜 이런 문제가 발생하는지 짐작 가시는게 있으면 좀 말씀해 주십시요. 정말 다급합니다;;
while(1)
{
usleep(1);
while ( (sharedLinkNode->ioBegin) == 1 )
{
sharedLinkNode->ioBegin = 100;
}
}
그럼 감사합니다. 답변 기다리겠습니다.
A 프로그램에서
A 프로그램에서
cur 과 newNode 는 아무 관련이 없으므로,
cur 를 고쳐봐야 newNode 는 변화하지 않을 것 같습니다.
결국 공유된 메모리의 ioBegin 은 줄창 -1 이겠습니다.
일단 여기까지.
프로그램 A의 while (
프로그램 A의
에서 사용된 cur 도 위와 마찬가지 이유로 공유메모리와는 전혀 상관없는 놈이므로
절대로 break 되지 않는 무한 busyloop 가 될 것 같습니다.
A 는 이쯤에서 마무리.
코드가 불완전한
코드가 불완전한 관계로 잠재적인 다른 버그들에 대한 추측은 어렵고.
적어주신 코드에서 눈에 보이는 논리적인 버그는 위에 적은 것 밖에 못 찾겠습니다.
솔직히, 정말로 이렇게 코딩하셨을까 하는 의문이 무럭무럭.
아마도 소스를 적당히 편집해서 적는 중에 오타가 생겼으리라 생각하는 중입니다.
아 코드가 불완전 하군요
위에서 cur은 linkNode* 형의 변수인데
*newNode = *cur;
과 같이 cur이 가리키고 있는 콘텐츠를 newNode가 가리키는 곳으로 복사하려는게
맞습니다.
혹시 공유메모리의 사용에서 이상한 부분은 없는지요??
newNode 는
newNode 는 공유메모리에 대한 포인터이고,
cur 는 아마도 로컬 포인터겠지요.
을 해서 말씀하신대로 컨텐츠 복사를 했습니다.
코드가 불완전하다는 부분이 바로 여긴데요,
만약,
의 의미로써의 cur 이라면 몰라도,
cur 이 정말로 프로그램A만의 로컬메모리에 대한 포인터라면 프로그램B 와는 상관없게됩니다.
위와 같은 리스트 탐색의 의미로 cur 을 고려해보려고 해도
라는 코드를 적어주셨기 때문에, 제겐 리스트탐색이 아니라 로컬변수로 여겨집니다.
리스트탐색이나 추가/삭제, 공유된 변수의 업데이트에 필히 고려해야 할 race condition 방어 미비로 인한 잠재적인 버그를 제외한다면, 공유메모리를 다루는 것에 이상은 없는 것 같습니다.
적어주신 예제코드와 유사한 샘플을 작성해서 두 줄을 수정한 후 돌려보니 잘 돌아가네요.
너무 감사합니다.
계속 tracking해주셔서 너무 감사합니다.
답글을 새로 막~~ 적다보니 갑자기 다른 리스트를 뒤지면서
(공유가 되지 않은 리스트) 공유메모리로 착각하지 않았나 라는 생각이 듭니다.
일단 지금 확인해 보고
결과를 잠시 후에 올리도록 하겠습니다.
고맙습니다~!!
혹시 쓰는프로세스와
혹시 쓰는프로세스와 읽는 프로세스의 소유자가 다른가요?
----------------------------------------------------------------------------
아뇨 그건 아니에요 ^^;;;
소유자도 같고 혹시 몰라서 퍼미션은 777에 root로 하고 있습니다.
감사합니다. 해결했습니다.
이것때문에 완전 고생했는데 진정 고맙습니다.
문제는 말하기 쪽팔리지만 ^^;;;;;; 공유되지 않은 큐를 공유된 큐라고 생각하고
마구 접근했습니다.
프로그램 B는 공유된 데이터를 건드리지만 프로그램 A는 공유된 데이터가 아닌
다른 데이터를 보면서 while을 걸어놓고 기다리고 있었습니다.
이런 문제일 거라고는 상상은 해봤지만(?) 계속 다른데 문제가 있을거라고 믿고있었는데
실제로 이 문제라고 거리를 좁히는데에는 계속 답글을 달아주신 님의 도움이
매우 컸습니다!!
다시한번 감사드리구요, 즐거운 하루 보내세요~!!
댓글 달기