1

对于我的任务,我必须使用轻量级进程和恒定大小的缓冲区来解决一个简化的康威问题。程序读取一个字符流,将该流打包成 10 个字符的块,然后将它们写成 24 个字符的行。井号 ('#') 字符将用作数据结束 (EOD) 标记值。我们必须实施以下更改:

在每个块之后插入一个额外的空白。

每对相邻的星号都被一个感叹号代替。仅当星号位于同一块中时,它们才被视为相邻。

我从来没有用 C 编程过,这让我很适应。我们得到了主程序三个进程和缓冲区操作的原型。到目前为止,经过几个小时后,我才设法让缓冲区正常工作。这是主例程以及函数原型和定义。

typedef struct {
    char *buf;         /* Buffer array */         
    int n;             /* Maximum number of slots */
    int front;         /* buf[(front+1)%n] is first item */
    int rear;          /* buf[rear%n] is last item */
    sem_t mutex;       /* Protects accesses to buf */
    sem_t slots;       /* Counts available slots */
    sem_t items;       /* Counts available items */
    } sbuf_t;

/* Function prototypes: */
void sbuf_init(sbuf_t *sp, int n);
void sbuf_deinit(sbuf_t *sp);
void sbuf_insert(sbuf_t *sp, char item);
char sbuf_remove(sbuf_t *sp);

void* ReadInput(void * vargp);    /* ReadInput thread routine prototype   */
void* Squash(void * vargp);       /* Squash thread routine prototype      */
void* PrintOutput(void * vargp);  /* PrintOutput thread routine prototype */


/* Global constants */
const int BLOCKMAX=10;      /* Length of input "blocks" */
const int LINEMAX=24;       /* Length of output "lines" */
const char EODsentinel='#'; /* End-Of-Data Sentinel value */


/* Global (shared) buffers */
sbuf_t rdbuf; /* Synchronized buffer between ReadInput and Squash   */
sbuf_t prbuf; /* Synchronized buffer between Squash and PrintOutput */


int main(int argc, char* argv[]) 
{
    pthread_t tidReadInput, tidSquash, tidPrintOutput;

    int rdbufsize;    /* buffer size between ReadInput and Squash   */
    int prbufsize;    /* buffer size between Squash and PrintOutput */


    /* Process input arguments */
    if (argc != 3) { 
        printf("usage: %s <rdbufsize> <prbufsize>\n", argv[0]);
        printf("  Using defaults: <rdbufsize=4> <prbufsize=7>\n");
       rdbufsize = 4;
       prbufsize = 7;
    }
    else
    {
        rdbufsize = atoi(argv[1]);
        prbufsize = atoi(argv[2]);
    }

    /* Create shared FIFO buffers */
    sbuf_init(&rdbuf, rdbufsize);
    sbuf_init(&prbuf, prbufsize);

    /* Create threads and wait for them to finish */
    Pthread_create(&tidReadInput,   NULL, ReadInput,   NULL);
    Pthread_create(&tidSquash,      NULL, Squash,      NULL);
    Pthread_create(&tidPrintOutput, NULL, PrintOutput, NULL);

    Pthread_join(tidPrintOutput, NULL);


    /* Clean up shared FIFO buffers */
    printf("\n---cleaning up---\n");
    sbuf_deinit(&rdbuf);
    sbuf_deinit(&prbuf);

    printf("\n---finished---\n");
    exit(0);
}

这是缓冲区操作。

/* Create an empty, bounded, shared FIFO buffer with n slots */
void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = Calloc(n, sizeof(char)); 
    sp->n = n;                       /* Buffer holds max of n items */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear */
    Sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking */
    Sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots */
    Sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}

/* Clean up buffer sp */
void sbuf_deinit(sbuf_t *sp)
{
    Free(sp->buf);
}

/* Insert item onto the rear of shared buffer sp */
void sbuf_insert(sbuf_t *sp, char item)
{
    P(&sp->slots);                   /* Wait for available slot */
    P(&sp->mutex);               /* Lock the buffer */
        sp->buf[(++sp->rear)%(sp->n)] = item;   /* Insert the item */
    V(&sp->mutex);               /* Unlock the buffer */
    V(&sp->items);                   /* Announce available item */
}

/* Remove and return the first item from buffer sp */
char sbuf_remove(sbuf_t *sp)
{
    char item;
    P(&sp->items);                   /* Wait for available item */
        P(&sp->mutex);               /* Lock the buffer */
            item = sp->buf[(++sp->front)%(sp->n)];  /* Remove the item */
        V(&sp->mutex);               /* Unlock the buffer */
    V(&sp->slots);                   /* Announce available slot */
    return item;
}

这是我的 3 个例程以及到目前为止我所拥有的。

/* ReadInput thread routine */
void* ReadInput(void * vargp)
{
    char ch;
    char newline;

    scanf("%c%c", &ch, &newline);

    while (ch != EODsentinel)
    {
        sbuf_insert(&rdbuf, ch);

        scanf("%c%c", &ch, &newline);
    }
    sbuf_insert(&rdbuf, EODsentinel);

    printf("ReadInput finished\n");

    return NULL;
}

/* Squash thread routine */
void* Squash(void * vargp)
{
    char ch;

    ch = sbuf_remove(&rdbuf);
    while (ch != EODsentinel)
    {
        sbuf_insert(&prbuf, ch);

        ch = sbuf_remove(&rdbuf);
    }
    sbuf_insert(&prbuf, EODsentinel);

    printf("Squash finished\n");

    return NULL;
}

/* PrintOutput thread routine */
void* PrintOutput(void * vargp)
{
    char ch;

    ch = sbuf_remove(&prbuf);
    while (ch != EODsentinel)
    {
        printf("%c", ch);

        ch = sbuf_remove(&prbuf);
    }

    printf("\n");

    printf("PrintOutput finished\n");

    return NULL;
}

我现在所做的所有代码都是读取输入,在缓冲区之间传递并打印出来。我知道我需要做什么,但不确定如何去做。我需要将换行逻辑添加到PrintOutput,将空格添加逻辑添加到ReadInput,并将星号感叹号逻辑添加到Squash。我的主要问题是使用缓冲区并在适当的地方添加逻辑。C 对我来说是新的,这很令人困惑。

4

0 回答 0