使用共享内存的服务器-客户端模型

问题描述 投票:0回答:1

我有以下程序,但无法使其在客户端和服务器之间正确同步。 运行后,我的程序总是在客户端和试图进入临界区的服务器之间发生冲突。 正如您将看到的,我使用带有共享内存的 systemV 信号量,以便进程相互通信。

我做错了什么?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>

#define SHM_SIZE 1024  // make it a 1K shared memory segment
#define MAX_FILES 10
#define MAX_LINES 10

/* Union semun */
union semun {
    int val;                  /* value for SETVAL */
    struct semid_ds *buf;     /* buffer for IPC_STAT, IPC_SET */
    unsigned short *array;    /* array for GETALL, SETALL */
};

// Semaphore operations
struct sembuf wait_server = {0, -1, SEM_UNDO};
struct sembuf signal_server = {0, 1, SEM_UNDO};
struct sembuf wait_client = {1, -1, SEM_UNDO};
struct sembuf signal_client = {1, 1, SEM_UNDO};

// Shared data structure between threads
struct SharedData {
    char shared_memory[SHM_SIZE];
    int start_line;
    int end_line;
    int file_index;
    int max_requests;
    int client_request; // Store the client's request number
};

void free_resources(int shm_id, int sem_id) {
    /* Delete the shared memory segment */
    shmctl(shm_id, IPC_RMID, NULL);
    /* Delete the semaphores */
    semctl(sem_id, 0, IPC_RMID, 0);
    semctl(sem_id, 1, IPC_RMID, 0);
}

/* Semaphore P - down operation, using semop */
int sem_P(int sem_id, int sem_num) {
    struct sembuf sem_d;

    sem_d.sem_num = sem_num;
    sem_d.sem_op = -1;
    sem_d.sem_flg = 0;
    if (semop(sem_id, &sem_d, 1) == -1) {
        perror("# Semaphore down (P) operation ");
        return -1;
    }
    return 0;
}

/* Semaphore V - up operation, using semop */
int sem_V(int sem_id, int sem_num) {
    struct sembuf sem_d;

    sem_d.sem_num = sem_num;
    sem_d.sem_op = 1;
    sem_d.sem_flg = 0;
    if (semop(sem_id, &sem_d, 1) == -1) {
        perror("# Semaphore up (V) operation ");
        return -1;
    }
    return 0;
}

/* Semaphore Init - set a semaphore's value to val */
int sem_Init(int sem_id, int sem_num, int val) {
    union semun arg;

    arg.val = val;
    if (semctl(sem_id, sem_num, SETVAL, arg) == -1) {
        perror("# Semaphore setting value ");
        return -1;
    }
    return 0;
}

int main(int argc, char *argv[]) {
    // Passing arguments to variables
    int N = atoi(argv[1]);    // Number of clients
    int K = atoi(argv[2]);    // Total number of files
    int L = atoi(argv[3]);    // Number of requests per client

    int shm_id;
    int sem_id;
    struct SharedData *data;
    int pid;

    /* Create a new shared memory segment */
    shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0660);
    if (shm_id == -1) {
        perror("Shared memory creation");
        exit(EXIT_FAILURE);
    }

    /* Create a new semaphore id */
    sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | 0660);
    if (sem_id == -1) {
        perror("Semaphore creation ");
        shmctl(shm_id, IPC_RMID, (struct shmid_ds *)NULL);
        exit(EXIT_FAILURE);
    }

    /* Set the value of the semaphores to 0 */
    if (sem_Init(sem_id, 0, 0) == -1 || sem_Init(sem_id, 1, 0) == -1) {
        free_resources(shm_id, sem_id);
        exit(EXIT_FAILURE);
    }

    /* Attach the shared memory segment */
    data = (struct SharedData *)shmat(shm_id, NULL, 0);
    if (data == NULL) {
        perror("Shared memory attach ");
        free_resources(shm_id, sem_id);
        exit(EXIT_FAILURE);
    }

    data->max_requests = L;
    int sleeptime;

    // Register the signal handler for client finished
    for (int i = 0; i < N; i++) {
        /* New process */
        sleeptime = random() % 10;
        if ((pid = fork()) == -1) {
            perror("fork");
            free_resources(shm_id, sem_id);
            exit(EXIT_FAILURE);
        }
        if (pid == 0) {
            printf("# I am the child process with process id: %d\n", getpid());
            int j = 0;
            while (j < data->max_requests) {
                /* Child process */
                //sem_V(sem_id, 1); // Signal server to process the request
                //sem_P(sem_id, 0); // Wait for server to finish
                data->file_index = rand() % MAX_FILES + 1;
                data->start_line = rand() % MAX_LINES + 1;
                data->end_line = rand() % (MAX_LINES - data->start_line) + data->start_line;
                printf("(%d): Client %d request %d\n", getpid(), i, j);
                data->client_request = j+1;  // Set the client's request number
                sem_V(sem_id, 1); // Signal server to process the request

                // Wait for the server to process the request
                sem_P(sem_id, 0); // Wait for server to finish
                printf("(%d): Server processed request %d\n", getpid(), j);
                j++;
                printf("j is %d \n ",j);
            }
            /* Child process */
            exit(EXIT_SUCCESS);
        } else {
            /* Server process */
            int j = 0;
            while (j < data->max_requests) {
                // sleep(5);
                /* Wait for child process */
               
                sem_V(sem_id, 0); // Signal client to continue 
                sem_P(sem_id, 1); // Wait for client to request
                printf("# I am the server process with process id: %d\n", getpid());
                // Process client requests here
                printf("(%d): processing client requests\n", getpid());
                // Example: Send a response to clients through shared memory
                strcpy(data->shared_memory, "Response from server");
                
                j++;
            }
            wait(NULL);
        }
        
    }

    // Clear resources
    free_resources(shm_id, sem_id);

    return 0;
}


c synchronization fork semaphore shared-memory
1个回答
0
投票

信号量代码不是问题。没关系。

问题出在这一行:

data->end_line = rand() % (MAX_LINES - data->start_line) + data->start_line;

有时会导致除以零(只是不是立即)并产生

SIGFPE
。这将终止/中止子线程。

父级看不到这一点,因为它陷入了

semop
调用中。所以家长会永远等待。

所以,事情看起来

semop
挂起/失败,但它不是

如果parent进程收到

SIGFPE
,它将中止并且shell会报告这一点。但是,这个
SIGFPE
是“沉默”的。它隐藏在等待的父母下面。 shell 只会看到父终止,在我们使用
SIGINT
停止它之后,它是
ctrl-c

为了找到这个错误,我制作了一个[大部分]重写的版本,其中包含很多的调试代码,我将在下面包含这些代码。

我通过运行

gdb
下的代码发现了这一点。

但是...

  1. 最初,
    gdb
    只是显示父级挂在
    semop
    中。
  2. gdb
    下,默认操作是
    gdb
    遵循 parent 流程,而不是 fork 之后的 child 流程。
    我必须告诉
  3. gdb
  4. 跟随
    孩子
    而不是父母 然后,
  5. gdb
  6. 困住了
    SIGFPE
    并停止了执行。
    
    
这是重构后的代码。是有注释的。正如所写,它将运行直至完成。要验证上述行

错误,请使用-DBUG进行编译:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>

#define SHM_SIZE 1024                   // make it a 1K shared memory segment
#define MAX_FILES 10
#define MAX_LINES 10

/* Union semun */
union semun {
    int val;                            /* value for SETVAL */
    struct semid_ds *buf;               /* buffer for IPC_STAT, IPC_SET */
    unsigned short *array;              /* array for GETALL, SETALL */
};

// Semaphore operations
struct sembuf wait_server = { 0, -1, SEM_UNDO };
struct sembuf signal_server = { 0, 1, SEM_UNDO };
struct sembuf wait_client = { 1, -1, SEM_UNDO };
struct sembuf signal_client = { 1, 1, SEM_UNDO };

// Shared data structure between threads
struct SharedData {
    char shared_memory[SHM_SIZE];
    int start_line;
    int end_line;
    int file_index;
    int max_requests;
    int client_request;                 // Store the client's request number
};

void
free_resources(int shm_id, int sem_id)
{
    /* Delete the shared memory segment */
    shmctl(shm_id, IPC_RMID, NULL);
    /* Delete the semaphores */
    semctl(sem_id, 0, IPC_RMID, 0);
    semctl(sem_id, 1, IPC_RMID, 0);
}

/* Semaphore P - down operation, using semop */
int
sem_P(int sem_id, int sem_num)
{
    struct sembuf sem_d;

    sem_d.sem_num = sem_num;
    sem_d.sem_op = -1;
    sem_d.sem_flg = 0;
    if (semop(sem_id, &sem_d, 1) == -1) {
        perror("# Semaphore down (P) operation ");
        return -1;
    }
    return 0;
}

/* Semaphore V - up operation, using semop */
int
sem_V(int sem_id, int sem_num)
{
    struct sembuf sem_d;

    sem_d.sem_num = sem_num;
    sem_d.sem_op = 1;
    sem_d.sem_flg = 0;
    if (semop(sem_id, &sem_d, 1) == -1) {
        perror("# Semaphore up (V) operation ");
        return -1;
    }
    return 0;
}

/* Semaphore Init - set a semaphore's value to val */
int
sem_Init(int sem_id, int sem_num, int val)
{
    union semun arg;

    arg.val = val;
    if (semctl(sem_id, sem_num, SETVAL, arg) == -1) {
        perror("# Semaphore setting value ");
        return -1;
    }
    return 0;
}

int
main(int argc, char *argv[])
{
    // Passing arguments to variables
    int N = atoi(argv[1]);              // Number of clients
    int K = atoi(argv[2]);              // Total number of files
    int L = atoi(argv[3]);              // Number of requests per client

    int shm_id;
    int sem_id;
    struct SharedData *data;
    int pid;

    printf("N=%d K=%d L=%d\n",N,K,L);

    /* Create a new shared memory segment */
    shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0660);
    if (shm_id == -1) {
        perror("Shared memory creation");
        exit(EXIT_FAILURE);
    }

    /* Create a new semaphore id */
    sem_id = semget(IPC_PRIVATE, 2, IPC_CREAT | 0660);
    if (sem_id == -1) {
        perror("Semaphore creation ");
        shmctl(shm_id, IPC_RMID, (struct shmid_ds *) NULL);
        exit(EXIT_FAILURE);
    }

    /* Set the value of the semaphores to 0 */
    if (sem_Init(sem_id, 0, 0) == -1 || sem_Init(sem_id, 1, 0) == -1) {
        free_resources(shm_id, sem_id);
        exit(EXIT_FAILURE);
    }

    /* Attach the shared memory segment */
    data = (struct SharedData *) shmat(shm_id, NULL, 0);
    if (data == NULL) {
        perror("Shared memory attach ");
        free_resources(shm_id, sem_id);
        exit(EXIT_FAILURE);
    }

    data->max_requests = L;
    //int sleeptime;

    // Register the signal handler for client finished
    for (int i = 0; i < N; i++) {
        /* New process */
        //sleeptime = random() % 10;
        if ((pid = fork()) == -1) {
            perror("fork");
            free_resources(shm_id, sem_id);
            exit(EXIT_FAILURE);
        }
        if (pid == 0) {
            printf("# I am the child process with process id: %d\n", getpid());
            int j = 0;

            while (j < data->max_requests) {
                /* Child process */
                // sem_V(sem_id, 1); // Signal server to process the request
                // sem_P(sem_id, 0); // Wait for server to finish
                data->file_index = rand() % MAX_FILES + 1;
                data->start_line = rand() % MAX_LINES + 1;

// NOTE/BUG: this can produce an integer divide by zero which produces SIGFPE
#if BUG
                data->end_line = rand() % (MAX_LINES - data->start_line) + data->start_line;
#else
                data->end_line = rand();
// NOTE/FIX: this just prevents the SIGFPE but may not be exactly the same
                int div = (MAX_LINES - data->start_line) + data->start_line;
                if (div != 0)
                    data->end_line /= div;
#endif

                printf("(%d): Client %d request %d\n", getpid(), i, j);
                data->client_request = j + 1;   // Set the client's request number
                sem_V(sem_id, 1);       // Signal server to process the request

                // Wait for the server to process the request
                sem_P(sem_id, 0);       // Wait for server to finish
                printf("(%d): Server processed request %d\n", getpid(), j);
                j++;
                printf("j is %d \n ", j);
            }
            /* Child process */
            exit(EXIT_SUCCESS);
        }
        else {
            /* Server process */
            int j = 0;

            while (j < data->max_requests) {
                // sleep(5);
                /* Wait for child process */

                sem_V(sem_id, 0);       // Signal client to continue
                sem_P(sem_id, 1);       // Wait for client to request
                printf("# I am the server process with process id: %d\n", getpid());
                // Process client requests here
                printf("(%d): processing client requests\n", getpid());
                // Example: Send a response to clients through shared memory
                strcpy(data->shared_memory, "Response from server");

                j++;
            }
            wait(NULL);
        }

    }

    // Clear resources
    free_resources(shm_id, sem_id);

    return 0;
}

这是我的调试版本。它有很多调试代码,包括
semop

的定时版本。如果发生超时,父进程将立即执行

wait
来收割子进程并取回
status
(显示
SIGFPE
)。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
#include <ctype.h>
#include <string.h>
#include <sys/file.h>

#define SHM_SIZE 1024                   // make it a 1K shared memory segment
#define MAX_FILES 10
#define MAX_LINES 10

pid_t pid_dog;
pid_t pid_self;
pid_t pid_par;
pid_t pid_cld;

int opt_d;                              // 1=use watchdog
int opt_f;                              // 1=use flock on log
int opt_u;                              // 1=unified/single log
int opt_T;                              // 1=timeout (ms)

int shm_id = -1;
int sem_par = -1;
int sem_cld = -1;

// Union semun
union semun {
    int val;                            // value for SETVAL
    struct semid_ds *buf;               // buffer for IPC_STAT, IPC_SET
    unsigned short *array;              // array for GETALL, SETALL
};

// Shared data structure between threads
struct SharedData {
    char shared_memory[SHM_SIZE];
    int client_request;
    int start_line;
    int end_line;
    int file_index;
    int max_requests;
};

#define dbgprtattr(_lvl) \
    __attribute__((__format__(__printf__,_lvl,_lvl + 1)))

FILE *xflog;
double tsczero;
unsigned long long seqno;               // sequence number

void
free_resources(int code)
{

    // Delete the shared memory segment
    if (pid_self == pid_par) {
        if (shm_id >= 0)
            shmctl(shm_id, IPC_RMID, NULL);

        // Delete the semaphore
        if (sem_par >= 0)
            semctl(sem_par, 0, IPC_RMID, 0);
        if (sem_cld >= 0)
            semctl(sem_cld, 0, IPC_RMID, 0);
    }

    exit(code);
}

int
semnow(int sem_id)
{
    int val = semctl(sem_id, 0, GETVAL);

    return val;
}

const char *
semprt(int sem_id)
{
    const char *tag;

    if (sem_id == sem_par)
        tag = "sem_par";
    else
        tag = "sem_cld";

#if 1
    static char buf[100];
    sprintf(buf,"%s/%d",tag,semnow(sem_id));
    tag = buf;
#endif

    return tag;
}

double
tscgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_MONOTONIC,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    sec -= tsczero;

    return sec;
}

const char *
pidshow(pid_t pid)
{
    const char *tag;

    do {
        if ((pid == pid_dog) && opt_d) {
            tag = "DOG";
            break;
        }

        if (pid == pid_par) {
            tag = "PAR";
            break;
        }

        tag = "CLD";
    } while (0);

    return tag;
}

void dbgprtattr(1)
dbgprt(const char *fmt,...)
{
    int sverr = errno;
    char buf[1000];
    va_list ap;
    FILE *xfcur;

    char *bp = buf;
    const char *tag = pidshow(pid_self);
    bp += sprintf(bp,"[%llu/%.9f/%s",seqno,tscgetf(),tag);
    ++seqno;

    do {
        if (tag[0] != 'P')
            break;

        if (pid_cld <= 0) {
            bp += sprintf(bp,"/NCO");
            break;
        }

        // FIXME/CAE -- this does _not_ detect a zombie (unreaped) child
        int err = kill(pid_cld,0);
        if (err >= 0) {
            bp += sprintf(bp,"/AOK");
            break;
        }

        bp += sprintf(bp,"/WTF");
    } while (0);

    bp += sprintf(bp,"] ");

    va_start(ap,fmt);
    bp += vsprintf(bp,fmt,ap);
    va_end(ap);

    xfcur = xflog;
    if (xfcur == NULL)
        xfcur = stdout;

    if (opt_f)
        flock(fileno(xfcur),LOCK_EX);

    fputs(buf,xfcur);
    fflush(xfcur);

    if (opt_f)
        flock(fileno(xfcur),LOCK_UN);

    errno = sverr;
}

void
reap_show(const char *who,pid_t pid,int status)
{
    char *bp;
    char msg[100];

    do {
        bp = msg;
        *bp = 0;

        if (WIFEXITED(status)) {
            bp += sprintf(bp," WIFEXITED code=%d",WEXITSTATUS(status));
            break;
        }

        if (WIFSIGNALED(status)) {
            bp += sprintf(bp," WIFSIGNALED signo=%d",WTERMSIG(status));
            break;
        }
    } while (0);

    dbgprt("%s: reaped pid=%s status=%8.8X --%s\n",
        who,pidshow(pid),status,msg);
}

void
reap_child(int err)
{
    int status;
    pid_t pid;

    dbgprt("reap_child: ENTER err=%d pid_cld=%d\n",err,pid_cld);

    while (1) {
        pid = wait(&status);
        if (pid <= 0)
            break;
        reap_show("reap_child",pid,status);
    }

    dbgprt("reap_child: EXIT\n");
}

void
dbgerr(const char *who,int code)
{

    dbgprt("dbgerr: %s (from %s)\n",strerror(errno),who);

    if (code == 0)
        code = 7;

    if (code)
        free_resources(code);
}

void
openlog(pid_t pid)
{
    char tail[100];
    char file[300];

    do {
        if (opt_u) {
            sprintf(tail,"com.log");
            break;
        }

        sprintf(tail,"%s.log",pidshow(pid));
    } while (0);

    for (char *cp = tail;  *cp != 0;  ++cp)
        *cp = tolower((unsigned char) *cp);

    const char *dir = getenv("GENDIR");
    if (dir == NULL)
        dir = ".";
    sprintf(file,"%s/%s",dir,tail);

    xflog = fopen(file,"a");
    setlinebuf(xflog);

    seqno = 0;
}

int
semxop(int semid, struct sembuf *sops, size_t nsops)
{
    struct timespec ts;
    long long tmout = opt_T;

    tmout *= 1000000;

    ts.tv_nsec = tmout % 1000000000;
    ts.tv_sec = tmout / 1000000000;

    int err = semtimedop(semid,sops,nsops,opt_T ? &ts : NULL);

    if ((err < 0) && (errno == EAGAIN)) {
        dbgprt("semxop: TIMEOUT val=%s\n",semprt(semid));
        reap_child(1);
        free_resources(1);
    }

    return err;
}

// Semaphore P - down operation, using semop
int
semunlock(int sem_id)
{
    struct sembuf sem_d;

    dbgprt("semunlock: ENTER sem_id=%s\n",semprt(sem_id));

    sem_d.sem_num = 0;
    sem_d.sem_op = -1;
    sem_d.sem_flg = 0;

    if (semxop(sem_id, &sem_d, 1) == -1) {
        dbgerr("semunlock",0);
        return -1;
    }

    dbgprt("semunlock: EXIT sem_id=%s\n",semprt(sem_id));

    return 0;
}

// Semaphore V - up operation, using semop
int
semlock(int sem_id)
{
    struct sembuf sem_d;

    dbgprt("semlock: ENTER sem_id=%s\n",semprt(sem_id));

    sem_d.sem_num = 0;
    sem_d.sem_op = 1;
    sem_d.sem_flg = 0;

    if (semxop(sem_id, &sem_d, 1) == -1) {
        dbgerr("semlock",0);
        return -1;
    }

    dbgprt("semlock: EXIT sem_id=%s\n",semprt(sem_id));

    return 0;
}

// Semaphore Wait - up operation, using semop
int
semwait(int sem_id)
{
    struct sembuf sem_d;

    dbgprt("semwait: ENTER sem_id=%s\n",semprt(sem_id));

    sem_d.sem_num = 0;
    sem_d.sem_op = 0;
    sem_d.sem_flg = 0;

    if (semxop(sem_id, &sem_d, 1) == -1) {
        dbgerr("semwait",0);
        return -1;
    }

    dbgprt("semwait: EXIT sem_id=%s\n",semprt(sem_id));

    return 0;
}

// Semaphore Init - set a semaphore's value to val
int
seminit(int sem_id, int sval)
{
    union semun arg;

    arg.val = sval;

    if (semctl(sem_id, 0, SETVAL, arg) == -1) {
        dbgerr("seminit",0);
        return -1;
    }

    return 0;
}

// Semaphore Create -- create a semaphore and set its value
int
semnew(int val)
{
    int sem_id;

    // Create a new semaphore id
    sem_id = semget(IPC_PRIVATE, 1, IPC_CREAT | 0660);
    if (sem_id == -1) {
        dbgerr("semnew",1);
    }

    if (seminit(sem_id,val) < 0)
        free_resources(1);

    return sem_id;
}

void
data_show(struct SharedData *data,int j)
{
    dbgprt("j=%d client_request=%d file_index=%d start_line=%d end_line=%d max_requests=%d\n",
        j,data->client_request,data->file_index,data->start_line,data->end_line,
        data->max_requests);
}

void
watchdog(pid_t pid)
{
    int status;

    if (! opt_u)
        openlog(pid_dog);

    pid_par = pid;

    while (1) {
        pid = wait(&status);
        if (pid < 0)
            break;
        reap_show("watchdog",pid,status);
    }

    fclose(xflog);
    exit(0);
}

void
docld(struct SharedData *data)
{
    int j = 0;

    while (j < data->max_requests) {
        dbgprt("# I am the child process -- j=%d\n",j);

        // Child process
        if (j > 0)
            semwait(sem_cld);

        dbgprt("docld: DATABEG\n");
        data->file_index = rand() % MAX_FILES + 1;
        data->start_line = rand() % MAX_LINES + 1;
#if BUG
        data->end_line = rand() %
            (MAX_FILES - data->start_line) + data->start_line;
#else
        int div = (MAX_FILES - data->start_line) + data->start_line;
        if (div == 0) {
            dbgprt("docld: fatal div=%d\n",div);
            free_resources(97);
        }
        data->end_line = rand() % div;
#endif
        data->client_request = j;
        dbgprt("docld: DATAEND\n");

        semlock(sem_cld);

        semunlock(sem_par);
        data_show(data,j);

        j++;
    }

    // Child process
    dbgprt("child done\n");
    fclose(xflog);
    exit(EXIT_SUCCESS);
}

void
dopar(struct SharedData *data)
{
    int j = 0;

    while (j < data->max_requests) {
        dbgprt("# I am the parent process -- j=%d\n",j);

        semwait(sem_par);

#if 0
        char mystring[74];
#else
        char mystring[200];
#endif
        sprintf(mystring, "Client requested lines %d to %d from file %d\n",
            data->start_line, data->end_line, data->file_index);
        data_show(data,j);

        semlock(sem_par);
        semunlock(sem_cld);

        j++;
    }

    reap_child(0);
    dbgprt("parent done\n");

    fclose(xflog);
}

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

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        char *cp = *argv;
        if (*cp != '-')
            break;

        cp += 2;
        switch (cp[-1]) {
        case 'd':
            opt_d = 1;
            break;
        case 'f':
            opt_f = 1;
            break;
        case 'T':
            opt_T = (*cp != 0) ? atoi(cp) : 1000;
            break;
        case 'u':
            opt_u = 1;
            break;
        default:
            printf("unknown option -- '%s'\n",cp - 2);
            exit(1);
            break;
        }
    }

    // Passing arguments to variables
    if (argc != 3) {
        printf("usage: num_of_clients num_of_files num_of_requests\n");
        exit(1);
    }
    int N = atoi(argv[0]);              // Number of clients
    int K = atoi(argv[1]);              // Total number of files
    int L = atoi(argv[2]);              // Number of requests per client

    struct SharedData *data;
    int pid;

    tsczero = tscgetf();
    pid_par = getpid();
    pid_self = pid_par;
    pid_dog = pid_par;

    unlink("par.log");
    unlink("cld.log");
    unlink("com.log");
    unlink("dog.log");

    printf("opt_T=%d opt_d=%d opt_u=%d\n",opt_T,opt_d,opt_u);
    printf("N=%d K=%d L=%d\n",N,K,L);

    // Create a new shared memory segment
#if 0
    shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0660);
#else
    shm_id = shmget(IPC_PRIVATE, sizeof(*data), IPC_CREAT | 0660);
#endif
    if (shm_id == -1) {
        dbgerr("shmget",1);
    }

    // Create a new semaphore id
    sem_par = semnew(1);
    sem_cld = semnew(1);

    // Attach the shared memory segment
    data = shmat(shm_id, NULL, 0);
    if (data == NULL) {
        dbgerr("shmat",1);
    }

    // open single/unified log
    if (opt_u)
        openlog(pid_self);
    else
        opt_f = 0;

    data->max_requests = L;

    if (opt_d) {
        pid = fork();

        pid_self = getpid();

        if (pid != 0)
            watchdog(pid);
        else
            pid_par = pid_self;
    }

    for (int i = 0; i < N; i++) {
        seminit(sem_par,1);
        seminit(sem_cld,0);

        // New process
        pid_cld = fork();
        if (pid_cld < 0) {
            dbgerr("fork",1);
        }

        pid_self = getpid();

        do {
            if (opt_u)
                break;
            openlog(pid_self);
        } while (0);

        dbgprt("i=%d N=%d K=%d L=%d\n",i,N,K,L);

        // Child process
        if (pid_cld == 0)
            docld(data);

        // Parent process
        else
            dopar(data);
    }

    // Clear recourses
    free_resources(0);

    return 0;
}

测试我使用的程序:

./program -T -d -u 10 5 50

您的程序
没有

有这些选项,所以您可以使用: ./program 10 5 50

这是子日志:

[0/0.001266244/CLD] i=0 N=10 K=5 L=50 [1/0.001298536/CLD] # I am the child process -- j=0 [2/0.001307860/CLD] docld: DATABEG [3/0.001315689/CLD] docld: DATAEND [4/0.001329338/CLD] semlock: ENTER sem_id=sem_cld/0 [5/0.001342283/CLD] semlock: EXIT sem_id=sem_cld/1 [6/0.001350356/CLD] semunlock: ENTER sem_id=sem_par/1 [7/0.001364993/CLD] semunlock: EXIT sem_id=sem_par/0 [8/0.001371790/CLD] j=0 client_request=0 file_index=4 start_line=7 end_line=7 max_requests=50 [9/0.001377922/CLD] # I am the child process -- j=1 [10/0.001384828/CLD] semwait: ENTER sem_id=sem_cld/1 [11/0.002007042/CLD] semwait: EXIT sem_id=sem_cld/0 [12/0.002028876/CLD] docld: DATABEG [13/0.002033988/CLD] docld: DATAEND [14/0.002039242/CLD] semlock: ENTER sem_id=sem_cld/0 [15/0.002047293/CLD] semlock: EXIT sem_id=sem_cld/1 [16/0.002055879/CLD] semunlock: ENTER sem_id=sem_par/1 [17/0.002069514/CLD] semunlock: EXIT sem_id=sem_par/0 [18/0.002075485/CLD] j=1 client_request=1 file_index=6 start_line=4 end_line=5 max_requests=50 [19/0.002083478/CLD] # I am the child process -- j=2 [20/0.002095297/CLD] semwait: ENTER sem_id=sem_cld/1 [21/0.002134363/CLD] semwait: EXIT sem_id=sem_cld/0 [22/0.002151245/CLD] docld: DATABEG [23/0.002164216/CLD] docld: DATAEND [24/0.002176661/CLD] semlock: ENTER sem_id=sem_cld/0 [25/0.002191834/CLD] semlock: EXIT sem_id=sem_cld/1 [26/0.002206599/CLD] semunlock: ENTER sem_id=sem_par/1 [27/0.002226650/CLD] semunlock: EXIT sem_id=sem_par/0 [28/0.002239249/CLD] j=2 client_request=2 file_index=7 start_line=3 end_line=4 max_requests=50 [29/0.002249359/CLD] # I am the child process -- j=3 [30/0.002260278/CLD] semwait: ENTER sem_id=sem_cld/1 [31/0.002302774/CLD] semwait: EXIT sem_id=sem_cld/0 [32/0.002315361/CLD] docld: DATABEG [33/0.002322812/CLD] docld: DATAEND [34/0.002331089/CLD] semlock: ENTER sem_id=sem_cld/0 [35/0.002340748/CLD] semlock: EXIT sem_id=sem_cld/1 [36/0.002349374/CLD] semunlock: ENTER sem_id=sem_par/1 [37/0.002361950/CLD] semunlock: EXIT sem_id=sem_par/0 [38/0.002369377/CLD] j=3 client_request=3 file_index=2 start_line=3 end_line=8 max_requests=50 [39/0.002376160/CLD] # I am the child process -- j=4 [40/0.002383759/CLD] semwait: ENTER sem_id=sem_cld/1 [41/0.002476519/CLD] semwait: EXIT sem_id=sem_cld/0 [42/0.002486868/CLD] docld: DATABEG

请注意,我们
没有

看到关闭docld: DATAEND,因此子进程在它们之间中止(即)

rand
调用是问题所在。

这是带有附加
wait

调用的父日志:

[0/0.001215808/PAR/AOK] i=0 N=10 K=5 L=50
[1/0.001263264/PAR/AOK] # I am the parent process -- j=0
[2/0.001272759/PAR/AOK] semwait: ENTER sem_id=sem_par/1
[3/0.001385589/PAR/AOK] semwait: EXIT sem_id=sem_par/0
[4/0.001403069/PAR/AOK] j=0 client_request=0 file_index=4 start_line=7 end_line=7 max_requests=50
[5/0.001415180/PAR/AOK] semlock: ENTER sem_id=sem_par/0
[6/0.001426980/PAR/AOK] semlock: EXIT sem_id=sem_par/1
[7/0.001435772/PAR/AOK] semunlock: ENTER sem_id=sem_cld/1
[8/0.001452325/PAR/AOK] semunlock: EXIT sem_id=sem_cld/0
[9/0.001461888/PAR/AOK] # I am the parent process -- j=1
[10/0.001472132/PAR/AOK] semwait: ENTER sem_id=sem_par/1
[11/0.002075115/PAR/AOK] semwait: EXIT sem_id=sem_par/0
[12/0.002091506/PAR/AOK] j=1 client_request=1 file_index=6 start_line=4 end_line=5 max_requests=50
[13/0.002098502/PAR/AOK] semlock: ENTER sem_id=sem_par/0
[14/0.002106132/PAR/AOK] semlock: EXIT sem_id=sem_par/1
[15/0.002112009/PAR/AOK] semunlock: ENTER sem_id=sem_cld/1
[16/0.002122503/PAR/AOK] semunlock: EXIT sem_id=sem_cld/0
[17/0.002127650/PAR/AOK] # I am the parent process -- j=2
[18/0.002133836/PAR/AOK] semwait: ENTER sem_id=sem_par/1
[19/0.002234273/PAR/AOK] semwait: EXIT sem_id=sem_par/0
[20/0.002248679/PAR/AOK] j=2 client_request=2 file_index=7 start_line=3 end_line=4 max_requests=50
[21/0.002261339/PAR/AOK] semlock: ENTER sem_id=sem_par/0
[22/0.002274647/PAR/AOK] semlock: EXIT sem_id=sem_par/1
[23/0.002284569/PAR/AOK] semunlock: ENTER sem_id=sem_cld/1
[24/0.002294957/PAR/AOK] semunlock: EXIT sem_id=sem_cld/0
[25/0.002300563/PAR/AOK] # I am the parent process -- j=3
[26/0.002306849/PAR/AOK] semwait: ENTER sem_id=sem_par/1
[27/0.002410154/PAR/AOK] semwait: EXIT sem_id=sem_par/0
[28/0.002423106/PAR/AOK] j=3 client_request=3 file_index=2 start_line=3 end_line=8 max_requests=50
[29/0.002434989/PAR/AOK] semlock: ENTER sem_id=sem_par/0
[30/0.002447388/PAR/AOK] semlock: EXIT sem_id=sem_par/1
[31/0.002457822/PAR/AOK] semunlock: ENTER sem_id=sem_cld/1
[32/0.002468612/PAR/AOK] semunlock: EXIT sem_id=sem_cld/0
[33/0.002474043/PAR/AOK] # I am the parent process -- j=4
[34/0.002480116/PAR/AOK] semwait: ENTER sem_id=sem_par/1
[35/1.041000029/PAR/AOK] semxop: TIMEOUT val=sem_par/1
[36/1.041029481/PAR/AOK] reap_child: ENTER err=1 pid_cld=1903742
[37/3.102558362/PAR/WTF] reap_child: reaped pid=CLD status=00000088 -- WIFSIGNALED signo=8
[38/3.102589796/PAR/WTF] reap_child: EXIT

注意第 37 行:
status

00000088
,这是以信号 8 终止(在我的系统上是
SIGFPE
)。
    

© www.soinside.com 2019 - 2024. All rights reserved.