0

I have a C program that parent process create a reader thread and then forks a child process that the child creates multiple writer threads.

Writer threads insert elements into shared buffer correctly but the reader thread doesn't do anything! When I put all reader and writer threads in one process the program works correctly and the reader reads elements from the buffer! Both reader and writer use sem_t as semaphore and sem_wait and sem_post for manage access to buffer.

This is my program pseudo code:

int main()
{
initialize semaphores

create reader_thread(reader code)

fork child process(server)
}

int server()
{
create writer threads(writer code)
}

This is buffer structure:

typedef struct
{
    Req_info reqinfo[BUFFER_SIZE];
    char chunk[BUFFER_SIZE][MAX_CHUNK_SIZE];
    uint64_t chunk_size[BUFFER_SIZE];
    int Isnewfile[BUFFER_SIZE];     //1 means new file
    int Islastchunk[BUFFER_SIZE];   //1 means last chunk
    int ID[BUFFER_SIZE];
    int head;
    int tail;
    int numofelement;
#ifdef SEM_V
    sem_t full;
    sem_t empty;
    sem_t mutex;
#else
    pthread_mutex_t mutex;
    pthread_cond_t cond_read;
    pthread_cond_t cond_write;
#endif
} Buffer;

Buffer *buffer_ptr;


void writer()
{
#ifdef SEM_V
    sem_wait(&buffer_ptr->empty);
    sem_wait(&buffer_ptr->mutex);
#else
    pthread_mutex_lock(&buffer_ptr->mutex);

    if((buffer_ptr->tail + 1) % BUFFER_SIZE == buffer_ptr->head)
    pthread_cond_wait( &buffer_ptr->cond_write, &buffer_ptr->mutex );

    pthread_mutex_unlock(&buffer_ptr->mutex);

    pthread_mutex_lock(&buffer_ptr->mutex);
#endif

    if ((buffer_ptr->tail + 1) % BUFFER_SIZE != buffer_ptr->head)
    {

    memmove(buffer_ptr->chunk[buffer_ptr->tail], chunk, chunk_size);    //Write chunk into buffer
    buffer_ptr->chunk[buffer_ptr->tail][chunk_size] = '\0';

    buffer_ptr->chunk_size[buffer_ptr->tail] = chunk_size;          //Write chunk size into buffer

    buffer_ptr->Isnewfile[buffer_ptr->tail] = Isnewfile;

    buffer_ptr->Islastchunk[buffer_ptr->tail] = Islastchunk;

    buffer_ptr->reqinfo[buffer_ptr->tail] = reqinfo;

    buffer_ptr->ID[buffer_ptr->tail] = ID;

    buffer_ptr->tail = (buffer_ptr->tail + 1) % BUFFER_SIZE;

    }
#ifdef SEM_V
    sem_post(&buffer_ptr->mutex);
    sem_post(&buffer_ptr->full);
#else

    pthread_cond_signal(&buffer_ptr->cond_write);
    pthread_mutex_unlock(&buffer_ptr->mutex);
#endif
}


void reader()
{
#ifdef SEM_V
        sem_wait(&buffer_ptr->full);
#endif

        if (buffer_ptr->tail != buffer_ptr->head)
            {

        if(!first){
            gettimeofday(&ts, NULL);
            first = 1;
        }

        chunksize = buffer_ptr->chunk_size[buffer_ptr->head];           //Read chunk size from buffer

        memmove(chunk, buffer_ptr->chunk[buffer_ptr->head], chunksize);     //Read chunk from buffer
        chunk[chunksize] = '\0';

        Isnewfile = buffer_ptr->Isnewfile[buffer_ptr->head];
        Islastchunk = buffer_ptr->Islastchunk[buffer_ptr->head];

        reqinfo = buffer_ptr->reqinfo[buffer_ptr->head];

        ID = buffer_ptr->ID[buffer_ptr->head];

            buffer_ptr->head = (buffer_ptr->head + 1) % BUFFER_SIZE;

            }
        else{
#ifdef SEM_V
        sem_post(&buffer_ptr->empty);
#endif
        continue;
        }
#ifdef SEM_V
        sem_post(&buffer_ptr->empty);
#endif
}
MSH
  • 429
  • 3
  • 7
  • 20
  • 1
    What are you reading from/writing to? If it's just a normal C buffer, it won't work. You need to use shared memory. – Drew McGowen Aug 14 '14 at 14:23
  • 1
    How about showing at least some of the *actual* code? – Scott Hunter Aug 14 '14 at 14:31
  • @Drew McGowen, each writer thread read an image file chunk by chunk and write it into a shared buffer. The shared buffer is a structure with some arrays of fields. The reader thread reads elements from buffer and write them into one storage file. – MSH Aug 14 '14 at 14:57
  • Is it actually shared memory, though? Like @ScottHunter said, you should post *actual* code; your pseudocode doesn't describe enough. – Drew McGowen Aug 14 '14 at 14:58
  • @Drew McGowen, No it's a normal buffer not a shared memory. – MSH Aug 14 '14 at 15:10
  • 1
    There's your problem - normal buffers are not implicitly shared across `fork`. – Drew McGowen Aug 14 '14 at 15:33
  • @Drew McGowen, I tried to define the buffer as shared memory but the buffer struct size is greater than the standard shared memory size and I couldn't change the struct definition. So is there another solution for this problem? – MSH Aug 16 '14 at 13:28

1 Answers1

1

There are at least two issues here: 1) whether the sem_t full/empty/mutex is shared between the parent process and the child process; 2) whether the buffer is shared between the parent process and the child process.

1) Since the child process resides in a separate address space, it no longer shares the same sem_t with the parent process. So you need to explicitly make those semaphores to be shared. As a result, the reader and writer cannot be properly synchronized. You can refer to this post on how to share semaphore.

2) Similarly due to the copy-on-write mechanism, the reader thread in the parent process and the writer threads in the child process no longer share the same buffer after fork. So you also need to explicitly share the buffer between the parent and the child. There are several ways to do this.

In your case, since your struct Buffer contains both semaphores and buffer, you simply need to make it shared, which will resolve both 1) and 2).

Community
  • 1
  • 1
wangjunwww
  • 296
  • 2
  • 10