В unp2 book почему в примере Posix shm есть переполнение? - PullRequest
1 голос
/ 22 января 2011

Я не совсем понимаю код ниже. Почему происходит переполнение и почему используется sem_trywait()? Разве я не могу просто несколько раз проверить семафор, вращая while(sem_trywait(&ptr->nempty) == -1 && errno==EAGAIN);?

Спасибо, Джефф

server2.c:

#include        "cliserv2.h"
int main(int argc, char **argv)
{

        int             fd, index, lastnoverflow, temp;
        long    offset;
        struct shmstruct        *ptr;
        char* addr;
        if (argc != 2)
                err_quit("usage: server2 <name>");

                /* 4create shm, set its size, map it, close descriptor */
        shm_unlink(Px_ipc_name(argv[1]));               /* OK if this fails */
        addr =Px_ipc_name(argv[1]);
        fd = Shm_open(addr, O_RDWR | O_CREAT | O_EXCL, FILE_MODE);
        ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
                           MAP_SHARED, fd, 0);
        Ftruncate(fd, sizeof(struct shmstruct));
        Close(fd);

                /* 4initialize the array of offsets */
        for (index = 0; index < NMESG; index++)
                ptr->msgoff[index] = index * MESGSIZE;

                /* 4initialize the semaphores in shared memory */
        Sem_init(&ptr->mutex, 1, 1);
        Sem_init(&ptr->nempty, 1, NMESG);
        Sem_init(&ptr->nstored, 1, 0);
        Sem_init(&ptr->noverflowmutex, 1, 1);

                /* 4this program is the consumer */
        index = 0;
        lastnoverflow = 0;
        for ( ; ; ) {
                Sem_wait(&ptr->nstored);
                Sem_wait(&ptr->mutex);
                offset = ptr->msgoff[index];
                printf("index = %d: %s\n", index, &ptr->msgdata[offset]);
                if (++index >= NMESG)
                        index = 0;                              /* circular buffer */
                Sem_post(&ptr->mutex);
                Sem_post(&ptr->nempty);

                Sem_wait(&ptr->noverflowmutex);
                temp = ptr->noverflow;          /* don't printf while mutex held */
                Sem_post(&ptr->noverflowmutex);
                if (temp != lastnoverflow) {
                        printf("noverflow = %d\n", temp);
                        lastnoverflow = temp;
                }
        }

        exit(0);
}

client2.c:

#include        "cliserv2.h"

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

        int             fd, i, nloop, nusec;
        pid_t   pid;
        char    mesg[MESGSIZE];
        long    offset;
        struct shmstruct        *ptr;

        if (argc != 4)
                err_quit("usage: client2 <name> <#loops> <#usec>");
        nloop = atoi(argv[2]);
        nusec = atoi(argv[3]);

                /* 4open and map shared memory that server must create */
        fd = Shm_open(Px_ipc_name(argv[1]), O_RDWR, FILE_MODE);
        ptr = Mmap(NULL, sizeof(struct shmstruct), PROT_READ | PROT_WRITE,
                           MAP_SHARED, fd, 0);
        Close(fd);

        pid = getpid();
        for (i = 0; i < nloop; i++) {   
                Sleep_us(nusec);
                snprintf(mesg, MESGSIZE, "pid %ld: message %d", (long) pid, i);
                if (sem_trywait(&ptr->nempty) == -1) {
                        if (errno == EAGAIN) {
                                Sem_wait(&ptr->noverflowmutex);
                                ptr->noverflow++;
                                Sem_post(&ptr->noverflowmutex);
                                continue; 
                        } else
                                err_sys("sem_trywait error");
                }
                Sem_wait(&ptr->mutex);
                offset = ptr->msgoff[ptr->nput];
                if (++(ptr->nput) >= NMESG)
                        ptr->nput = 0;          /* circular buffer */
                Sem_post(&ptr->mutex);
                strcpy(&ptr->msgdata[offset], mesg);
                Sem_post(&ptr->nstored);
        }
        msync(ptr, sizeof(struct shmstruct), MS_SYNC);
        munmap(ptr, sizeof(struct shmstruct));
        exit(0);
}

1 Ответ

4 голосов
/ 22 января 2011

В 13.6 книга объясняет использование счетчика переполнения:

Счетчик переполнения

Существует вероятность того, что клиент хочет отправить сообщение, но все Слоты сообщений принимаются. Но если клиент на самом деле является сервером некоторых тип (возможно, FTP-сервер или HTTP сервер), клиент не хочет подождите, пока сервер освободит слот. Поэтому мы будем писать нашим клиентам чтобы они не блокировали а увеличить счетчик noverflow, когда Бывает. (...)

Итак, причина в том, что клиент никогда не должен блокировать, даже если он не может отправить сообщение. Спиннинг, как вы и предполагали, не лучше, чем просто использовать sem_wait() напрямую, что уже было рассмотрено ранее в книге. Автор только что продемонстрировал, как справиться с другой ситуацией, когда блокировка не нужна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...