我很难使用多个文件进行结构化工作。请帮忙?

时间:2011-11-07 05:18:40

标签: c unix pthreads header-files

我正在尝试解决消费者/生产者问题,我必须创建三个不同的类。

主类包括线程的创建和消费者/生产者逻辑

其他两个类是

  • 环形缓冲区的头文件
  • 包含环形缓冲区实现的文件

尝试编译时遇到以下错误:

ringbuf.c: In function ‘rb_init’:
ringbuf.c:10: warning: incompatible implicit declaration of built-in function ‘malloc’
ringbuf.c:10: error: invalid application of ‘sizeof’ to incomplete type ‘struct ringbuf_t’ 
ringbuf.c:12: error: dereferencing pointer to incomplete type

我还有很多其他错误,但是一旦我完成这个错误,我就可以自己处理。

这是缓冲区的头文件:

struct ringbuf_t 
{
    pthread_mutex_t mutex; /* lock to protect from simutaneous access to the buffer */
    pthread_cond_t cond_full; /* producer needs to wait when the buffer is full */
    pthread_cond_t cond_empty; /* consumer needs to wait when the buffer is empty */
    int bufsiz; /* size of the buffer; you may use an empty slot to differentiate the situation the buffer is full or empty */
    int front; /* index of the first element */
    int back; /* index next to the last element (or index to the first empty slot) */
    int count; //keeps track of the number of elements in the buffer
    char* buf; /* buffer itself */
};

/* return the pointer to the newl created and initialized ring buffer of the given size */
extern struct ringbuf_t* rb_init(int bufsiz);

/* reclaim the ring buffer */
extern void rb_finalize(struct ringbuf_t* rb);

/* return the current number of elements in the buffer */
extern int rb_size(struct ringbuf_t* rb);

/* return non-zero (true) if the buffer is currently full */
extern int rb_is_full(struct ringbuf_t* rb);

/* return non-zero (true) if the buffer is currently empty */
extern int rb_is_empty(struct ringbuf_t* rb);

/* insert (i.e., append) a character into the buffer; if the buffer is full, the caller thread will be blocked */
extern void rb_insert(struct ringbuf_t* rb, int c);

/* retrieve a character at the front of the ring buffer; if the buffer is empty, the caller thread will be blocked */
extern int rb_remove(struct ringbuf_t* rb);

这是缓冲区的实现:

#include <malloc.h>
#include <stdio.h>

struct ringbuf_t 
{
    pthread_mutex_t mutex; /* lock to protect from simutaneous access to the buffer */
    pthread_cond_t cond_full; /* producer needs to wait when the buffer is full */
    pthread_cond_t cond_empty; /* consumer needs to wait when the buffer is empty */
    int bufsiz; /* size of the buffer; you may use an empty slot to differentiate the situation the buffer is full or empty */
    int front; /* index of the first element */
    int back; /* index next to the last element (or index to the first empty slot) */
    int count; //keeps track of the number of elements in the buffer
    char* buf; /* buffer itself */
};


struct ringbuf_t* rb_init(int bufsiz)
{
    struct ringbuf_t* buffer = (struct ringbuf_t*)malloc(sizeof(struct ringbuf_t));

    buffer->bufsiz = bufsiz;
    buffer->front = 0;
    buffer->back = 0;
    buffer->count = 0;
}


/* reclaim the ring buffer */
void rb_finalize(struct ringbuf_t* rb)
{
    free(rb);
    pthread_mutex_destroy(&rb->mutex);
    printf("\nnotice - ring buffer finalized");
}



/* return the current number of elements in the buffer */
int rb_size(struct ringbuf_t* rb)
{
    return (rb->count);
}



/* return non-zero (true) if the buffer is currently full */
int rb_is_full(struct ringbuf_t* rb)
{
    return ((rb->count) == rb->bufsiz);
}



/* return non-zero (true) if the buffer is currently empty */
int rb_is_empty(struct ringbuf_t* rb)
{
    return ((rb->count) == 0);
}



/* insert (i.e., append) a character into the buffer; if the buffer is full, the caller thread will be blocked */
void rb_insert(struct ringbuf_t* rb, int c)
{
    char* temp;


    if(rb->count < rb->bufsiz)
    {
        if(rb->count == 0)
        {
            rb->front = 0;
            rb->back = 0;
            rb->buf = c;
            rb->count++;
        }
        else
        {
            if(rb->front < (rb->bufsiz - 1))
            {
                temp = rb->buf;
                temp = temp + rb->front + 1;
                temp = c;
                rb->front++;
            }
            else if(rb->front == (rb->bufsiz -1))
            {
                rb->front = 0;
                rb->buf = c;
            }
        }
    }
    else
    {
        printf("\nerror - trying to insert into full buffer");
    }
}



/* retrieve a character at the tail (back) of the ring buffer; if the buffer is empty, the caller thread will be blocked */
int rb_remove(struct ringbuf_t* rb)
{
    if(rb->count != 0)
    {
        count--;
        if(rb->back < (rb->bufsiz-1)
        {
            rb->back++;
        }
        else if(rb->back == (rb->bufsiz -1))
        {
            rb->back = 0;
        }
    }
    else
    {
        printf("\nerror - trying to remove from empty buffer");
    }

}

这是主要类:

#include <stdio.h>
#include <pthread.h>
#include <ringbuf.h>


    //creating a static ring buffer
struct ringbuf* mybuffer = rb_init(10);

int thisChar;

    /*
     consumer thread, reads one character at a time, sets the lock when addinga character to the ring buffer
     while locked it checks if the buffer is full, waits for a slot, and then continues.
     */
void* consumer(void* arg)
{
    printf("consumer started");

    while(thisChar != EOF)
    {
        pthread_mutex_lock(&(mybuffer->mutex));

        while(rb_is_empty(mybuffer))
            pthread_cond_wait(&(mybuffer->cond_full), &(mybuffer->mutex));

        printf("%s", (char)rb_remove(mybuffer));

        pthread_cond_signal(&(mybuffer->cond_empty));

        pthread_mutex_unlock(&(mybuffer->mutex));
    }
}

    /*
     producer thread, takes one character at a time from the buffer, (while the buffer is not empty)
     and prints it to the screen.
     */


void* producer(void* arg)
{
    printf("producer started");

    while ((thisChar = getchar()) != EOF)
    {

        pthread_mutex_lock(&(mybuffer->mutex));

        while(rb_is_full(mybuffer))
            pthread_cond_wait(&(mybuffer->cond_empty), &(mybuffer->mutex));

        rb_insert(mybuffer, thisChar);

        pthread_cond_signal(&(mybuffer->cond_full));

        pthread_mutex_unlock(&(mybuffer->mutex));
    }
}


int main()
{

        //declaring threads
    pthread_t t0, t1;


        //creating threads as condumer, producer
    p_thread_create(&t0, NULL, consumer, (void*)mybuffer);
    p_thread_create(&t1, NULL, producer, (void*)mybuffer);


    pthread_join(t0, NULL);
    pthread_join(t1, NULL);

    rb_finalize(mybuffer);

    return 0;
}

我错过了一些东西,但我需要先解决这个问题!请帮忙!

2 个答案:

答案 0 :(得分:6)

#include <malloc.h>行替换为#include <stdlib.h>。这将修复你在这里粘贴的错误(可能还有很多)。执行此操作后,请返回您的代码并移除拨打malloc(3)的所有演员:

struct ringbuf_t* buffer = (struct ringbuf_t*)malloc(sizeof(struct ringbuf_t));

当函数原型被推入语言时,(struct ringbuf_t*)大致{{1}}已经没有必要了。

答案 1 :(得分:3)

另见:

ringbuf.h

您的ringbuf.h标题应该是自包含且幂等的。因此,它应包括<pthread.h>

#ifndef RINGBUF_H_INCLUDED
#define RINGBUF_H_INCLUDED

#include <pthread.h>

struct ringbuf_t 
{
    pthread_mutex_t mutex; /* lock to protect from simutaneous access to the buffer */
    pthread_cond_t cond_full; /* producer needs to wait when the buffer is full */
    pthread_cond_t cond_empty; /* consumer needs to wait when the buffer is empty */
    int bufsiz; /* size of the buffer; you may use an empty slot to differentiate the situation the buffer is full or empty */
    int front; /* index of the first element */
    int back; /* index next to the last element (or index to the first empty slot) */
    int count; //keeps track of the number of elements in the buffer
    char* buf; /* buffer itself */
};

/* return the pointer to the newl created and initialized ring buffer of the given size */
extern struct ringbuf_t* rb_init(int bufsiz);

/* reclaim the ring buffer */
extern void rb_finalize(struct ringbuf_t* rb);

/* return the current number of elements in the buffer */
extern int rb_size(struct ringbuf_t* rb);

/* return non-zero (true) if the buffer is currently full */
extern int rb_is_full(struct ringbuf_t* rb);

/* return non-zero (true) if the buffer is currently empty */
extern int rb_is_empty(struct ringbuf_t* rb);

/* insert (i.e., append) a character into the buffer; if the buffer is full, the caller thread will be blocked */
extern void rb_insert(struct ringbuf_t* rb, int c);

/* retrieve a character at the front of the ring buffer; if the buffer is empty, the caller thread will be blocked */
extern int rb_remove(struct ringbuf_t* rb);

#endif /* RINGBUF_H_INCLUDED */

如果是我的标题,我还有一个额外的一行:

typedef struct ringbuf_t ringbuf_t;

我会编辑函数原型以丢失struct关键字。

这样做的好处是任何人都可以包含ringbuf.h,它只会对他们有效。

ringbuf.c

实现文件使用自己的标头至关重要;这为您提供了必要的交叉检查,表明标题准确反映了实施的内容。它也应该是包含的第一个标题;这给出了一个简单但有效的检查标题是自包含的。

除非您使用其扩展功能,否则不应使用<malloc.h><stdlib.h>声明malloc()等,除非您知道<malloc.h>中有哪些额外功能可供使用,否则应使用它们。

这导致:

#include "ringbuf.h"
#include <stdio.h>
#include <stdlib.h>

struct ringbuf_t* rb_init(int bufsiz)
{
    struct ringbuf_t* buffer = (struct ringbuf_t*)malloc(sizeof(struct ringbuf_t));

    buffer->bufsiz = bufsiz;
    buffer->front = 0;
    buffer->back = 0;
    buffer->count = 0;
}

/* reclaim the ring buffer */
void rb_finalize(struct ringbuf_t* rb)
{
    free(rb);
    pthread_mutex_destroy(&rb->mutex);
    printf("\nnotice - ring buffer finalized");
}

/* return the current number of elements in the buffer */
int rb_size(struct ringbuf_t* rb)
{
    return (rb->count);
}

/* return non-zero (true) if the buffer is currently full */
int rb_is_full(struct ringbuf_t* rb)
{
    return ((rb->count) == rb->bufsiz);
}

/* return non-zero (true) if the buffer is currently empty */
int rb_is_empty(struct ringbuf_t* rb)
{
    return ((rb->count) == 0);
}

/* insert (i.e., append) a character into the buffer; if the buffer is full, the caller thread will be blocked */
void rb_insert(struct ringbuf_t* rb, int c)
{
    char* temp;

    if(rb->count < rb->bufsiz)
    {
        if(rb->count == 0)
        {
            rb->front = 0;
            rb->back = 0;
            rb->buf = c;
            rb->count++;
        }
        else
        {
            if(rb->front < (rb->bufsiz - 1))
            {
                temp = rb->buf;
                temp = temp + rb->front + 1;
                temp = c;
                rb->front++;
            }
            else if(rb->front == (rb->bufsiz -1))
            {
                rb->front = 0;
                rb->buf = c;
            }
        }
    }
    else
    {
        printf("\nerror - trying to insert into full buffer");
    }
}

/* retrieve a character at the tail (back) of the ring buffer; if the buffer is empty, the caller thread will be blocked */
int rb_remove(struct ringbuf_t* rb)
{
    if(rb->count != 0)
    {
        count--;
        if(rb->back < (rb->bufsiz-1)
        {
            rb->back++;
        }
        else if(rb->back == (rb->bufsiz -1))
        {
            rb->back = 0;
        }
    }
    else
    {
        printf("\nerror - trying to remove from empty buffer");
    }
}

你应该使用fprintf(stderr, ...)而不是printf()进行诊断,你应该考虑如何在运行时关闭它们(或者更可能的是,如何打开它们)。

请注意,通常将系统提供的标头放在尖括号中(因此<stdio.h>)和用户提供的标头用双引号(因此"ringbuf.h")。

您的rb_init()函数应该完全初始化结构。这意味着互斥锁和两个条件变量都应该正确初始化。它还需要初始化(零)buf成员或分配适当的空间 - 更可能是后者。您的代码应检查分配是否成功,并且仅在分配的空间中使用。

您还应该检查是否适合使生产者和消费者线程操纵互斥锁和条件变量。如果它们与结构捆绑在一起,则与结构捆绑在一起的功能应该对互斥锁和条件执行必要的操作。这将允许您简化生产者和消费者只需调用环形缓冲区函数。显然,main()仍然会启动两个线程,但如果你的抽象正确,那么线程本身就不需要直接使用互斥量和条件;环形缓冲区库代码将为线程正确地执行此操作。这样做的一个优点是,您的图书馆可以一次性运营,所有消费者都可以从中受益。另一种方法是让每个生产者和消费者处理互斥和条件 - 这会放大错误的机会。在课堂上你不会在这个练习之后再次使用抽象,正确的分离和封装并不是那么重要,但在专业代码中,图书馆使人们能够轻松正确地使用代码是至关重要的。让他们犯错误。

的main.c

在C中,你无法使用函数调用初始化全局变量 - 在C ++中,你可以。

因此,这不会在C:

中编译
//creating a static ring buffer
struct ringbuf_t *mybuffer = rb_init(10);

您应该使用:

struct ringbuf_t *mybuffer = 0;

然后,在main()或从main()调用的函数 - 直接或间接 - 执行函数调用:

mybuffer = rb_init(10);

这将在您完成创建线程的任何工作之前。当您的rb_init()代码初始化互斥锁和条件变量时,您的main()将能够按照书面形式继续。

在此之前,你需要进行大量的清理工作。


免责声明我还没有编译代码来查看编译器的内容。

注意如果你使用GCC但是不能至少编译-Wall,最好是-Wextra(并清除任何(所有)警告),你是错过了一个非常重要的助手。我使用逆行代码库,我也要担心-Wmissing-prototypes -Wold-style-definition -Wstrict-prototypes。使用-Werror可能会有所帮助;它迫使你清理警告。