Operating System Program (circular buffer)

Posted on 2007-11-17 05:07  QT_pixy  阅读(862)  评论(4)    收藏  举报

关于Operating System建立thread的程序,多个thread共享一个circular buffer,按照一定的顺序对这个buffer进行操作。因为每个thread写入之后要sleep一段时间,然后把CPU分配到其他thread上。我这个程序可以正确运行,但是如果thread非常多,共同操作一个buffer,系统运行速度就会很慢。可能是因为CPU在多个thread之上不停的转换造成的。
下面是这个程序的要求说明。
 
   Write an ansi C program called q1.c that is
    invoked as follows:

        % q1 <max> <bufferSize> <nWriters> <nReaders> <resultsFile>

    The progam should create <nWriters + nReaders> threads/pthreads
    (not child processes).
    They share a circular buffer of size <bufferSize>.
    Each buffer slot is capable of holding 2 ints, namely the number of
    the thread (1 .. nWriters) and a second int in the range (1 .. <max>).
   
    Each writer thread repeatedly writes a pair of ints into the next free
    buffer slot.  These pairs are
    (threadNumber, 1), (threadNumber, 2), ... , (threadNumber, <max>).
    After writing one such pair, the thread sleeps a random length of time
    between 0 and .1 seconds.  Use nanosleep for this (% man nanosleep).

    Each reader thread repeatedly reads the next available (threadNumber, n)
    pair from the buffer and then appends them to the <resultFile> as
    threadNumber n\n
    i.e. the threadNumber followed by a single blank followed by the int
    followed by a newline character. (Note that some testing will be done
    with a script, so adhering to this output format is important.)
    In all, your program should output <nWriters>*<max> lines.
    After reading one such pair, the the thread sleeps a random length of time
    between 0 and .1 seconds.  Use nanosleep for this (% man nanosleep).

    The  threads should use all buffer slots,
    i.e. with indexes from 0 up to <bufferSize>-1.

    Example:  the call

        % q1 5 3 2 4 temp

    (i.e. max of 5, buffer size of 3, 2 writer threads, 4 reader threads
    and output going to a file called temp)
    could result in the following 10 lines being written to temp:
1 1
1 2
2 1
1 3
2 2
1 4
2 3
2 4
2 5
1 5
    Your solution should not make assumptions about thread scheduling or
    count on (or try to enforce) any particular alternation or sequencing
    among the threads.

Compiling
=========
    We will compile your programs using
        % cc -Wall -o q1 q1.c -lpthread



#define BUFLEN 100   /* define the length of buffer used by sprintf */
#define TRUE 1   /* truth status used by critical section */
#define FALSE 0   /* false status used by critical section */


#include 
<stdio.h>
#include 
<stdlib.h>
#include 
<pthread.h>
#include 
<string.h>
#include 
<time.h>
#include 
<fcntl.h>
#include 
<sys/stat.h>
#include 
<pthread.h>
#include 
<unistd.h>

/* global variable accessed by threads */

/* variables used to store the input integers */
int max;
int bufferSize;
int nWriters;
int nReaders;

int mutex = 1;   /* used by binary semaphore */
int read_number = 0;   /* count the number of pairs to be read */
int in = 0;   /* write position of the circular array */
int out = 0;   /* read position of the circular array */
int fd;   /* file descriptor */
int full = FALSE;   /* indicate status of the buffer when buffer size is 1 */

char buf[BUFLEN];   /* buffer used by sprintf */

struct timespec ts;   /* declaring a timespec struct */

/* define struct type */
typedef 
struct {
    
int threadNumber;
    
int number;
}
item;
item (
*Pbuffer)[];   /* declaring a pointer to the buffer */

/* function declaration */
void * Writers(int);
void * Readers(void *);
int TestAndSet(int *);

/* wait operation of the binary semaphore */
void wait(int *mux)
{
    
while(*mux == 0)
        ;
    
*mux = 0;
}


/* signal operation of the binary semaphore */
void signal(int *mux)
{
    
*mux = 1;
}


int main(int argc, char ** argv)
{
    
int thread_number;   /* record thread number */
    
int error;   /* indicates the error number */
    
int i;   /* used as a counter of the loop */
    
char* resultsFile;   /* store file name */
    pthread_t tid;   
/* store thread ID */

    
if (argc < 6)
    
{
        fprintf(stderr, 
"missing argument, usage: q1 <max> <bufferSize> <nWriters> <nReaders> <resultsFile>\n");
        exit(
-1);
    }


    
/* save arguments */
    max 
= atoi(argv[1]);
    bufferSize 
= atoi(argv[2]);
    nWriters 
= atoi(argv[3]);
    nReaders 
= atoi(argv[4]);
    resultsFile 
= argv[5];

    item buffer[bufferSize];   
/* make a new buffer used to store elements */
    Pbuffer 
= &buffer;   /* let globle pointer point to the buffer, then threads can access the buffer */

    srand(time(NULL));   
/*The pseudo-random number generator is initialized using the seed. */ 

    
/* establish the connection between a file and a file descriptor */
    
if ((fd = open(resultsFile, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1)
    
{
        perror(resultsFile);
        exit(
-1);
    }


    
/* create threads which will write the buffer, and pass thread numbers as argument to threads */
    
for (thread_number = 1; thread_number <= nWriters; thread_number++)
    
{
        
if ((error = pthread_create(&tid, NULL, (void *)Writers, (void *)thread_number)))
        
{
            fprintf(stderr, 
"Cannot create thread:%s\n", strerror(error));
            exit(
1);
        }

    }

    
/* create threads which will read the buffer */
    
for (i = 0; i < nReaders; i++)
    
{
        
if ((error = pthread_create(&tid, NULL, Readers, NULL)))
        
{
            fprintf(stderr, 
"Cannot create thread:%s\n", strerror(error));
            exit(
1);
        }

    }


    
/* Wait until the last thread terminates. Any thread can terminates only when all things on the buffer have been written on file */
    pthread_join(tid, NULL);

    
/* close the file descriptor */
    close(fd);

    
return 0;
}


/* Write buffer */
void * Writers(int thread_number)
{
    
struct timespec ts;   /*  The structure encapsulates seconds and ns */
    
int counter = 1;   /* counte the number from 1 to max */ 

    
while (counter <= max)
    
{
        wait(
&mutex);

        
/* buffer is not full */
        
if ((in + 1% bufferSize != out)
        
{
            
/************ critical section *************/

            
/* write pairs on buffer */
            (
*Pbuffer)[in].threadNumber = thread_number;
            (
*Pbuffer)[in].number = counter;

            
in = (in + 1% bufferSize;   /* increase the writing position on buffer */
            counter
++;   /* increase the counter */

            signal(
&mutex);

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */
        }

        
/* when buffer size is 1, and buffer is not full */
        
else if (bufferSize == 1 && full == FALSE)
        
{
            
/************ critical section *************/

            
/* write pairs on buffer */
            (
*Pbuffer)[in].threadNumber = thread_number;
            (
*Pbuffer)[in].number = counter;

            full 
= TRUE;   /* set the buffer to be full */

            counter
++;   /* increase the counter */

            signal(
&mutex);    

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */
        }

        
/* buffer is full */
        
else
        
{
            signal(
&mutex);

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */ 
        }

    }

    
return NULL;
}


/* Read buffer */
void * Readers(void * arg)
{
    
struct timespec ts;   /*  The structure encapsulates seconds and ns */

    
/* there are totally nWriters * max pairs to be read */
    
while(read_number < nWriters * max)
    
{
        wait(
&mutex);

        
/************ critical section *************/

        
/* if all pairs have been read, then terminate */
        
if (read_number >= nWriters * max)
            
break;

        
/* buffer is not empty */
        
if (in != out)
        
{
            
/* read buffer and write to file */
            sprintf(buf, 
"%d %d\n", (*Pbuffer)[out].threadNumber, (*Pbuffer)[out].number);
            write(fd, buf, strlen(buf));
            
            
out = (out + 1% bufferSize;   /* increase the reading position on buffer */
        
            read_number
++;   /* increase the number of pairs which have been read */

            signal(
&mutex);

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */
        }

        
/* when buffer size is 1, and buffer is full */
        
else if (bufferSize == 1 && full == TRUE)
        
{
            
/* read buffer and write to file */
            sprintf(buf, 
"%d %d\n", (*Pbuffer)[out].threadNumber, (*Pbuffer)[out].number);
            write(fd, buf, strlen(buf));

            full 
= FALSE;    /* set the buffer to be full */

            read_number
++;   /* increase the number of pairs which have been read */

            signal(
&mutex);

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */
        }

        
/* when buffer is empty */
        
else
        
{
            signal(
&mutex);

            
/************ remainder section *************/

            ts.tv_nsec 
= rand() % 100000000;
            nanosleep(
&ts, NULL);   /* the thread sleeps a random length of time between 0 and .1 seconds */
        }

    }

    
return NULL;
}

博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3