2017-04-03 8 views
1

C에서 명령 줄에 입력 된 숫자가 0에서 9로 계산되는 프로그램을 만들려고합니다.이 프로그램에서 총 3 개의 프로세스를 만드는 두 개의 fork() 호출이 있어야합니다. 그런 다음 각 프로세스가 다른 n % 3을 담당하는 숫자 순서로 실행되도록 최소 1 개의 세마포어를 사용해야합니다.내 세마포어가 분기 된 프로세스 내에서 순서가 잘못된 이벤트를 허용하는 이유는 무엇입니까?

문제점은 내가 사용하고있는 세마포어에도 불구하고, 프로그램이 상당히 규칙적으로 작동하지 않는 것 같습니다. 나는 현재 각 프로세스가 자신이 지정한 세마포어를 강제로 기다릴 게이트 스타일 시스템을 사용하고 있으며, 일단 끝나면 sem_post는 다음에 실행될 프로세스의 세마포어이다. 나는 이것이 가장 유익하거나 가장 논리적으로 효율적인 방법이 아니라는 것을 알고 있지만, 똑같은 이슈를 가진 처음 두 번의 시도가 끝난 후에도 효과가있을 것이라고 확신합니다.

내가 잘못한 부분에 대해 누구나 나에게 의견을 제시 할 수 있다면 매우 감사하게 생각합니다.

#include <stdio.h> 
    #include <stdlib.h> 
    #include <time.h> 
    #include <sys/types.h> 
    #include <unistd.h> 
    #include <semaphore.h> 
    #include <fcntl.h> 

    #define SEM_NAME1 "/sem1.mutex" 
    #define SEM_NAME2 "/sem2.mutex" 
    #define SEM_NAME3 "/sem3.mutex" 

    int main(int argc, char *argv[]) { 

     if(argc <= 1){ 
      printf("No arguments were provided so there is no number to count to"); 
      return 1; 
     } 

     // Create the 3 semaphores needed 
     sem_t *sem1; 
     sem_t *sem2; 
     sem_t *sem3; 

     //initialize to 0 
     sem1 = sem_open(SEM_NAME1, O_CREAT, O_RDWR, 0); 
     if (sem1==SEM_FAILED) { 
      printf("%s sem_open failed!", SEM_NAME1); 
      return (-1); 
     } 
     //initialize to 1 
     sem2 = sem_open(SEM_NAME2, O_CREAT, O_RDWR, 1); 
     if (sem2==SEM_FAILED) { 
      printf("%s sem_open failed!", SEM_NAME2); 
      return (-1); 
     } 
     //initialize to 1 
     sem3 = sem_open(SEM_NAME3, O_CREAT, O_RDWR, 1); 
     if (sem3==SEM_FAILED) { 
      printf("%s sem_open failed!", SEM_NAME3); 
      return (-1); 
     } 

     pid_t pid; 
     pid_t pid2; 
     pid = fork(); 

     if(pid == 0){ 
      pid2 = fork(); 
     } 
     // Shared fork variables 
     int counter = 0; 
     int ranOnce = 0; 
     int max_num = atoi(argv[1]); 

     while(counter <= max_num){ 
      if(pid > 0){ 
       printf("%d",getpid()); 
       if(ranOnce == 0){ 
        counter += 1; 
        ranOnce = 1; 
       } 
       sem_wait(sem2); 
       printf(" %d \n", counter); 
       counter += 3; 
       sem_post(sem3); 
      } 
      else if(pid2 == 0){ 
       printf("%d",getpid()); 
       if(ranOnce == 0){ 
        counter += 0; 
        ranOnce = 1; 
       } 
       sem_wait(sem1); 
       printf(" %d \n", counter); 
       counter += 3; 
       sem_post(sem2); 
      } 
      else{ 
       printf("%d",getpid()); 
       if(ranOnce == 0){ 
        counter += 2; 
        ranOnce = 1; 
       } 
       sem_wait(sem3); 
       printf(" %d \n", counter); 
       counter += 3; 
       sem_post(sem1); 
      } 
     } 
     //sem_unlink(SEM_NAME1); 
     //sem_unlink(SEM_NAME2); 
     //sem_unlink(SEM_NAME3); 
     return 0; 
    } 

답변

2

세마포어의 초기 값은 역 당신은있는 동시에 sem2 및 sem3 프로세스를 활성화

sem1 = sem_open(SEM_NAME1, O_CREAT, O_RDWR, 1); 
sem2 = sem_open(SEM_NAME2, O_CREAT, O_RDWR, 0); 
sem3 = sem_open(SEM_NAME3, O_CREAT, O_RDWR, 0); 

해야합니다, 그래서 그들은 동시에 작동하지만 :

내 코드는 다음과 같습니다 순서가 잘못된 이벤트를 제거하기 위해이를 동기화해야합니다.

0

죄송합니다. 귀하의 코드는 설계대로 작동하지 않습니다.

fork이 호출 된 후 각 프로세스에는 "공유"변수의 자체 복사본이 있습니다. 스레드와 달리 SysV 공유 메모리 프리미티브를 통해 설정 한 공유 메모리 영역을 사용해야합니다.

따라서 각 프로세스는 자체 복사본을 증가시키고 counter이 아닙니다. 또한

, 제 [while 절 포함] 공유 변수에 대한 모든 액세스는 잠금 캡슐화되어야한다. 당신은 내가 개별 사본을 사용해야합니다 내가 공유 변수를 사용하려면 세 번째 문장 또는 암시하는 경우


는 잘 모르겠어요. // Shared fork variables을, 그래서 당신 공통 카운터를 원했다는 것을 추론 :

나는 당신의 코멘트를보고 있었다. IMO, 당신은이 하나 싶어

나는 각은 카운터 변수의 자신의 개인 사본에 액세스하고 그 세마포어 게이트의 목적임을 알고 십자가를 체크. 스레드가 다시 실행될 수 있으면 두 프로세스가 모두 인쇄를 완료 했으므로 시퀀스의 다음 문자는 counter의 현재 값보다 3이 앞당겨집니다.

나는 그것을 이해할 수 있도록 앱을 단순화하기 위해 코드를 다시 작성했습니다.

깨끗한 라운드 로빈 시퀀스가 ​​표시되지 않습니다. 당신이 있다면, 지금, 모두 잘되고, 나는 버그를 도입했을 수도 있습니다. 난 shmget 등을 사용하여 공유 메모리 글로벌 카운터를 추가했습니다. al. 그것은 하나 씩 증가해야하지만, 가끔 뒤로 미끄러 져 [주의해야 : 그것은 늦게 여기 그 문제 :-)의 일부가 될 수 있도록 내가 피곤 해요] 어쨌든

, 여기에 내가 생각 해낸거야 : 여기

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <time.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <fcntl.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 

#define SEM_NAME1 "/sem1.mutex" 
#define SEM_NAME2 "/sem2.mutex" 
#define SEM_NAME3 "/sem3.mutex" 

typedef struct tsk { 
    int tsk_idx; 
    sem_t *tsk_sem; 
    pid_t tsk_pid; 
    char tsk_name[100]; 
} tsk_t; 

#define NTASK  3 

tsk_t tsklist[NTASK]; 

// Shared fork variables 
volatile int counter = 0; 
volatile int ranOnce = 0; 
int max_num; 
volatile int *globptr; 

void 
dochild(tsk_t *tsk) 
{ 
    int stopflg; 
    int tidx; 
    tsk_t *tsk2; 

    while (1) { 
     sem_wait(tsk->tsk_sem); 
     stopflg = (counter > max_num); 

     if (! stopflg) { 
      printf("Tidx:%d Pid:%d Seq:%d",tsk->tsk_idx,tsk->tsk_pid,*globptr); 
      *globptr += 1; 
      if (ranOnce == 0) { 
       counter += 1; 
       ranOnce = 1; 
      } 
      printf(" Counter:%d\n", counter); 
      fflush(stdout); 
      counter += 3; 
     } 

     tidx = tsk->tsk_idx + 1; 
     tidx %= NTASK; 
     tsk2 = &tsklist[tidx]; 

     sem_post(tsk2->tsk_sem); 

     if (stopflg) 
      break; 
    } 

    exit(0); 
} 

int 
main(int argc, char *argv[]) 
{ 
    tsk_t *tsk; 
    int tidx; 
    void *sptr; 

    if (argc <= 1) { 
     printf("No arguments were provided so there is no number to count to\n"); 
     //return 1; 
    } 
    else 
     max_num = atoi(argv[1]); 

    int shmfd = shmget(IPC_PRIVATE,sizeof(int),0600); 
    sptr = shmat(shmfd,NULL,0); 
    globptr = sptr; 
    *globptr = 0; 

    // Create the 3 semaphores needed 
    for (tidx = 0; tidx < NTASK; ++tidx) { 
     tsk = &tsklist[tidx]; 
     tsk->tsk_idx = tidx; 

     sprintf(tsk->tsk_name,"/sem%d.mutex",tidx); 

     if (max_num == 0) { 
      sem_unlink(tsk->tsk_name); 
      continue; 
     } 

     tsk->tsk_sem = sem_open(tsk->tsk_name, O_CREAT, O_RDWR, 
      0644,(tidx == 0) ? 1 : 0); 

     if (tsk->tsk_sem == SEM_FAILED) { 
      printf("%s sem_open failed! -- %s\n",tsk->tsk_name,strerror(errno)); 
      return (-1); 
     } 
    } 

    if (max_num == 0) 
     return 0; 

    for (tidx = 0; tidx < NTASK; ++tidx) { 
     tsk = &tsklist[tidx]; 
     tsk->tsk_pid = fork(); 
     if (tsk->tsk_pid != 0) 
      continue; 

     tsk->tsk_pid = getpid(); 
     dochild(tsk); 
    } 

    for (tidx = 0; tidx < NTASK; ++tidx) { 
     tsk = &tsklist[tidx]; 
     waitpid(tsk->tsk_pid,NULL,0); 
    } 

#if 1 
    for (tidx = 0; tidx < NTASK; ++tidx) { 
     tsk = &tsklist[tidx]; 
     sem_unlink(tsk->tsk_name); 
    } 
#endif 

    shmdt(sptr); 

    return 0; 
} 

는 실행의 출력입니다 :

Tidx:0 Pid:18563 Seq:0 Counter:1 
Tidx:0 Pid:18563 Seq:1 Counter:4 
Tidx:0 Pid:18563 Seq:2 Counter:7 
Tidx:0 Pid:18563 Seq:3 Counter:10 
Tidx:1 Pid:18564 Seq:4 Counter:1 
Tidx:1 Pid:18564 Seq:5 Counter:4 
Tidx:1 Pid:18564 Seq:6 Counter:7 
Tidx:1 Pid:18564 Seq:7 Counter:10 
Tidx:2 Pid:18565 Seq:4 Counter:1 
Tidx:2 Pid:18565 Seq:9 Counter:4 
Tidx:2 Pid:18565 Seq:10 Counter:7 
Tidx:2 Pid:18565 Seq:11 Counter:10 
+0

난 당신이 세 번째 문장에 함축되어 있는지 확실하지 않습니다 내가 공유 변수를 사용하려면 아니면 개인을 사용하는 것을 사본. 나는 각각이 카운터 변수의 개별 사본을 액세스하고 있으며 이것이 세마포어 게이트의 목적이라는 것을 알고 있습니다. 스레드가 다시 실행될 수 있으면 두 프로세스가 모두 인쇄를 완료 했으므로 시퀀스의 다음 문자는 counter의 현재 값보다 3이 앞당겨집니다. – KM529