세마포어의 버그 발견?

익명 사용자의 이미지

---s_test.c(세마포 함수부분)----------------------------------------

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define _UW_SOURCE

int d_sem_opr(semid, sem_num, flag)
int semid; /* semid */
int flag; /* 1LOCK, 2UNLOCK */
{
int num;
pid_t sempid;
union semun {
int val;
struct semid_ds * buf;
ushort * array;
} sval;

/*----- */
static struct sembuf op_lock[1] = {
0, -1, SEM_UNDO /* then increment sem#0 by 1 */
};

static struct sembuf op_unlock[1] = {
0, 1, (IPC_NOWAIT|SEM_UNDO)
/* decrement sem#0 by 1 (sets it to 0) */
};

sempid = semctl(semid, sem_num, GETPID, sval);

if(sempid == 0) {
sval.val = 1;
semctl(semid, sem_num, SETVAL, sval);
}

op_lock[0].sem_num = sem_num;
op_unlock[0].sem_num = sem_num;

/*===== LOCK =====*/
if (flag == 1)
{
if (semop (semid, &op_lock[0], 1) < 0 && errno != 0) {
#ifdef _LIB_DEBUG
printf ("[d_sem_opr] semop SEND LOCK \n");
#endif
return(-1);
}
/*===== UNLOCK =====*/
} else if (flag == 2) {

if (semop (semid, &op_unlock[0], 1) < 0 && errno != 0) {
#ifdef _LIB_DEBUG
printf ("[d_sem_opr] semop UNLOCK \n");
#endif
return(-1);
}
}

return(0);
}

--------------end of s_test.c------------------------------------

--------------semtest.c------------------------------------------

#include
#include
#include
#include

#define LOCK(a) d_sem_opr(a, 0, 1)
#define UNLOCK(a) d_sem_opr(a, 0, 2)

#define SND_LOCK(a) d_sem_opr(a, 1, 1)
#define SND_UNLOCK(a) d_sem_opr(a, 1, 2)

int sem_test(int semid)
{
char ch;

puts("before SND_LOCK");
SND_LOCK(semid);

puts("after SND_LOCK");
LOCK(semid);

puts("after LOCK");
fflush(stdin);
printf("\ncontinue? ");
scanf("%c", &ch);

if(ch != 'Y' && ch != 'y') {
UNLOCK(semid);
SND_UNLOCK(semid);
return(-1);
}

UNLOCK(semid);
puts("after UNLOCK");

sleep(1);

LOCK(semid);
puts("after LOCK");
// usleep(1000); <=== 주목!!!!!

UNLOCK(semid);
puts("after UNLOCK");
SND_UNLOCK(semid);
puts("after SND_UNLOCK");
puts("\n++++++++++++++++++\n");
return(0);
}

int main()
{
int semid;

if((semid = semget(1111, 3, IPC_CREAT | 0666)) < 0) {
#ifdef _LIB_DEBUG
perror("[d_msgget]semget");
#endif
return(-1);
}

while(1) {
if(sem_test(semid) < 0)
break;
}
}

-------------end of semtest.c -----------------------------

-------------st.c -----------------------------------------
#include
#include
#include
#include

#define LOCK(a) d_sem_opr(a, 0, 1)
#define UNLOCK(a) d_sem_opr(a, 0, 2)

#define SND_LOCK(a) d_sem_opr(a, 1, 1)
#define SND_UNLOCK(a) d_sem_opr(a, 1, 2)

int main()
{
int semid;

if((semid = semget(1111, 3, IPC_CREAT | 0666)) < 0) {
#ifdef _LIB_DEBUG
perror("[d_msgget]semget");
#endif
return(-1);
}

LOCK(semid);
printf("LOCK\n");

sleep(2);

UNLOCK(semid);
printf("UNLOCK\n");

}

-----------------end of st.c ----------------------------------

컴파일
cc -c s_test.c
cc -c semtest.c
cc -c st.c
cc -o semtest s_test.o semtest.o
cc -o st s_test.o st.o

설명

1. semtest의 로직

SND_LOCK
LOCK
입력 대기
UNLOCK

LOCK
//usleep(1000); <== 주목!!!
UNLOCK
SND_LOCK

2. st의 로직

LOCK
sleep()
UNLOCK

test1

먼저 semtest를 세개를 순서대로 띄웁니다.(편의상 순서대로 s1, s2, s3라
고 부르겠습니다)

1. s1, s2, s3를 다 띄웁니다.
(s1에서 continue?란 메시지가 나옴, s2, s3는 before SND_LOCK 상태)
2. st를 띄웁니다.
3. s1의 continue?라는 곳에 y라고 입력합니다.
4. st에서 LOCK이란 메시지를 볼수 있음
5. st는 2초후에 UNLOCK을 한후에 종료
6. st가 UNLOCK한 후에 s1에서 또다시 continue?라는 표시가 나옵니다.
(이게 이상합니다. 당연히 s2 가 LOCK을 얻어야 하는데요)
7. 2로 반복합니다.

제어권은 계속 s1 => st => s1 => st로 반복됩니다.

s2, s3는 결코 lock을 얻지 못하고 소외됩니다.

test2
설명에 (<=== 주목!!!)이라고 되어 있는 부분을 풀고 같은 테스트를 합니
다.

같은 실험을 반복하면 s1 => st => s2 => st => s3 => st순으로 원래 의
도대로 돌아갑니다.

질문

test1과 test2에서 알수 있듯이 <== 주목이라는 부분에 usleep을 넣지 않
으면 정상적으로 작동하지 않습니다.

usleep을 넣지 않더라도 test1이 제대로 동작할 수 있는 방법이 있을까요?
(s1 => st => s2 => st = s3 순서)

아니면 이게 세마포의 버그라고 판단 할 수 있을까요?

고수님들의 많은 조언을 바랍니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.