Click here to Skip to main content
15,896,444 members
Articles / Programming Languages / C#

An Introduction to Threads, Critical Sections, and Synchronization

Rate me:
Please Sign up or sign in to vote.
4.00/5 (16 votes)
29 Sep 2008CPOL5 min read 67.8K   254   42  
With the days of the single cored processor drawing to a close and users demanding more robust user interfaces by the day, knowledge of multi-threaded programming techniques is quickly becoming a requirement of any competitive application developer.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace threadtesting
{
    public class BufferQueue
    {
        private byte[] buff;
        private int head, tail, size;
        private volatile int count;
        private Mutex appendmut, readmut, countmut;

        // Constructor
        public BufferQueue(int size)
        {
            appendmut = new Mutex();
            readmut = new Mutex();
            countmut = new Mutex();
            buff = new byte[size];
            this.size = size;
            head = 0;
            tail = 0;
            count = 0;
        }

        // Get the number of bytes in the buffer
        public int Count { get { return count; } }
        // The maximum size of the buffer
        public int Size { get { return size; } }

        // Append bytes to the buffer
        public void append(byte[] data) { if (data != null) append(data, 0, data.Length); }
        public void append(byte[] data, int offset, int length)
        {
            if (data == null) return;
            if (data.Length < offset + length) { throw new Exception("array index out of bounds. offset + length extends beyond the length of the array."); }

            appendmut.WaitOne();
            // We need to acquire the mutex so that this.tail doesn't change.
            for (int i = 0; i < length; i++)
                buff[(i + this.tail) % this.size] = data[i + offset];
            this.tail = (length + this.tail) % this.size;
            countmut.WaitOne();
            // We need to acquire the mutex so that this.count doesn't change.
            this.count = this.count + length;
            if (this.count > this.size)
                throw new Exception("Buffer overflow error.");
            countmut.ReleaseMutex();
            appendmut.ReleaseMutex();
        }

        // Read bytes from the buffer
        public string read()
        {
            byte[] data = new byte[size];
            read(data);
            return System.Text.ASCIIEncoding.ASCII.GetString(data);
        }
        public int read(byte[] data) { if (data != null) return read(data, 0, data.Length); else return 0; }
        public int read(byte[] data, int offset, int length)
        {
            if (data == null) return 0;
            if (data.Length < offset + length) throw new Exception("array index out of bounds. offset + length extends beyond the length of the array.");

            int readlength = 0;

            // We need to acquire the mutex so that this.head doesn't change.
            readmut.WaitOne();

            for (int i = 0; i < length; i++)
            {
                if (i == count) break;
                data[i + offset] = buff[(i + head) % this.size];
                readlength++;
            }
            this.head = (readlength + this.head) % this.size;

            // We need to acquire the mutex so that this.count doesn't change.
            countmut.WaitOne();
            this.count = this.count - readlength;
            countmut.ReleaseMutex();
            readmut.ReleaseMutex();
            return readlength;
        }

        // Peek at the buffer
        public string peek()
        {
            byte[] data = new byte[size];
            peek(data);
            return System.Text.ASCIIEncoding.ASCII.GetString(data);
        }
        public int peek(byte[] data) { if (data != null) return peek(data, 0, data.Length); else return 0; }
        public int peek(byte[] data, int offset, int length)
        {
            if (data == null) return 0;
            if (data.Length < offset + length) throw new Exception("array index out of bounds. offset + length extends beyond the length of the array.");

            int readlength = 0;

            // We need to acquire the mutex so that this.head doesn't change.
            readmut.WaitOne();

            for (int i = 0; i < length; i++)
            {
                if (i == count) break;
                data[i + offset] = buff[(i + head) % this.size];
                readlength++;
            }

            readmut.ReleaseMutex();
            return readlength;
        }

        public void clear()
        {
            readmut.WaitOne();
            appendmut.WaitOne();
            countmut.WaitOne();
            this.head = 0;
            this.tail = 0;
            this.count = 0;
            countmut.ReleaseMutex();
            appendmut.ReleaseMutex();
            readmut.ReleaseMutex();
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions