生产者,消费者的几个例子

在多线程中传递数据,免不了要用生产者,消费者模式,几个例子:

Java:

public class BlockingQueueInputStream extends InputStream {
private static final String TAG = "BlockingQueueIS";

private BlockingQueue<byte[]> mData = null;
private byte[] mDataCache = null;
private boolean mFinished = false;

public BlockingQueueInputStream(int capacity) {
mData = new LinkedBlockingQueue<>(capacity);
mFinished = false;
}

public BlockingQueueInputStream(BlockingQueue<byte[]> blockingQueue) {
mData = blockingQueue;
}

public void reset() {
mFinished = false;
}

public BlockingQueue<byte[]> getBlockingQueue() {
return mData;
}

public int write(byte[] buffer) {
if(mFinished) {
return -1;
}
try {
// a deep copy since the blocking queue only store reference
 byte[] temp = Arrays.copyOf(buffer, buffer.length);
mData.put(temp);
return temp.length;
} catch (InterruptedException e) {
Dbg.e(TAG, "Write Exception", e);
return -1;
}
}

public int read() {
throw new UnsupportedOperationException("Single-byte read not supported");
}

public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}

public int read(byte[] s, int offset, int length) throws IOException {
if (mDataCache != null && mDataCache.length >= length) {
System.arraycopy(mDataCache, 0, s, offset, length);
byte[] newDataCache = new byte[mDataCache.length - length];
System.arraycopy(mDataCache, length, newDataCache, 0, newDataCache.length);
mDataCache = newDataCache;
return length;
}

int total_read = 0;
if (mDataCache != null && mDataCache.length < length) {
System.arraycopy(mDataCache, 0, s, offset, mDataCache.length);
total_read += mDataCache.length;
mDataCache = null;
}

while (total_read < length) {
try {
byte[] bytes = null;
while (!mFinished || !mData.isEmpty()) {
bytes = mData.poll(100, TimeUnit.MILLISECONDS);
if (bytes != null) {
break;
}
}
if (bytes == null) {
if (total_read > 0) {
return total_read;
} else {
return -1;
}
}
// We have extra data, save it to the cache and waiting for next read.
 if (total_read + bytes.length > length) {
mDataCache = new byte[total_read + bytes.length - length];
System.arraycopy(bytes, bytes.length - mDataCache.length, mDataCache, 0, mDataCache.length);
System.arraycopy(bytes, 0, s, total_read + offset, bytes.length - mDataCache.length);
return length;
} else {
System.arraycopy(bytes, 0, s, offset + total_read, bytes.length);
total_read += bytes.length;
}
} catch (InterruptedException e) {
Dbg.e(TAG, "Read Exception", e);
return -1;
}
}
return total_read;
}

public void close() {
mFinished = true;
mData.clear();
}
}

Java

public class MyBlockingQueue {

private Queue queue = new LinkedList();

/**
 * Make a blocking Dequeue call so that we'll only return when the queue has
 * something on it, otherwise we'll wait until something is put on it.
 *
 * @returns This will return null if the thread wait() call is interrupted.
 */
 public synchronized Object dequeue() {
Object msg = null;
while (queue.isEmpty()) {
try {
wait(100);
} catch (InterruptedException e) {
// Error return the client a null item
 return msg;
}
}
msg = queue.remove();
Log.i("myblocking", "queue poll " + queue.size());
return msg;
}

/**
 * Enqueue will add an object to this queue, and will notify any waiting
 * threads that there is an object available.
 */
 public synchronized void enqueue(Object o) {
queue.add(o);
Log.i("myblocking", "queue put " + queue.size());
// Wake up anyone waiting for something to be put on the queue.
 notifyAll();
}

public boolean isEmpty() {
return queue.isEmpty();
}
}

使用OKIO的

public class FifoInputStream extends InputStream {
private static final String TAG = FifoInputStream.class.getSimpleName();
int mSampleRate;
int mDelay;
private Pipe mPipe;
private volatile boolean mStopped = false;

public FifoInputStream(int sampleRate, int delay) {
mSampleRate = sampleRate;
mDelay = delay;
mStopped = false;
mPipe = new Pipe(mSampleRate * 2 * 10); //10s Buffer
 mPipe.sink().timeout().timeout(10000, TimeUnit.MILLISECONDS);
mPipe.source().timeout().timeout(10000, TimeUnit.MILLISECONDS);
}

@Override
 public int read() throws IOException {
return 0;
}

public void write(byte[] buffer) throws IOException {
if (mStopped) {
Log.i(TAG, "write stopped");
return;
}
int length = buffer.length;
int available = length;
if (mDelay > 0) {
mDelay = mDelay - buffer.length * 1000 / (2 * mSampleRate);
} else {
while (available > 0 && !mStopped) {
Buffer temp = new Buffer();
temp.write(buffer, length - available, available);
Log.i(TAG, "write " + available);
mPipe.sink().write(temp, available);
}
}
}

@Override
 public int read(byte[] buffer, int offset, int length) throws IOException {
if(mStopped) {
Log.i(TAG, "read stopped -1");
return -1;
}
Buffer temp = new Buffer();
// return -1 when exhausted after sink closed; if length < available, return available immediately
 long i = mPipe.source().read(temp, length);
if (i != -1) {
temp.read(buffer, offset, (int) i);
} else {
mPipe.source().close();
}
Log.i(TAG, "Fifo read " + i);
return (int) i;
}

public void close() throws IOException {
Log.i(TAG, "Fifo close");
mStopped = true;
mPipe.sink().close();
mPipe.source().close();
}
}




C++

    class RingBuffer {
    private:
        int8_t * pBase;
        int32_t mLength;
        //pRead point to the first address of real data
        int8_t * pRead = NULL;
        //pWrite point to the address after the last real data
        int8_t * pWrite = NULL;
        pthread_mutex_t ringbuffer_mutex = PTHREAD_MUTEX_INITIALIZER;
        pthread_cond_t ringbuffer_written_cond = PTHREAD_COND_INITIALIZER;
        int32_t getFreeCount();
        int32_t getDataCount();
    public:
        RingBuffer(int length);
        ~RingBuffer();
        int32_t read(void * buffer, int32_t size);
        int32_t write(void * buffer, int32_t size);
    };
int32_t mobvoi::RingBuffer::getDataCount() {
    int32_t count = pWrite - pRead;
    if (count < 0) {
        count += mLength;
    }
    return count;
}

int32_t mobvoi::RingBuffer::getFreeCount() {
    int count = 0;
    if (pRead > pWrite) {
        count = pRead - pWrite - 1;
    } else {
        count = mLength - (pWrite - pRead + 1);
    }
    return (count > 0) ? count : 0;
}
// read from ring buffer to liner buffer, blocking
int32_t mobvoi::RingBuffer::read(void * buffer, int32_t count) {
    pthread_mutex_lock(&ringbuffer_mutex);
    if (count >= mLength) {
        pthread_mutex_unlock(&ringbuffer_mutex);
        return -1;
    }
    while (count > getDataCount()) {
        pthread_cond_wait(&ringbuffer_written_cond, &ringbuffer_mutex);
    }
    if (pRead <= pWrite) {
        memcpy(buffer, pRead, count);
        pRead += count;
    } else {
        int8_t * end = pBase + mLength;
        int32_t r2e = end - pRead;
        if (count <= r2e) {
            memcpy(buffer, pRead, count);
            pRead += count;
            if (pRead == end) {
                pRead = pBase;
            }
        } else {
            memcpy(buffer, pRead, r2e);
            memcpy(buffer + r2e, pBase, count - r2e);
            pRead = pBase + count - r2e;
        }
    }
    pthread_mutex_unlock(&ringbuffer_mutex);
    return count;
}
// write data from liner buffer to ring buffer, non blocking
int32_t mobvoi::RingBuffer::write(void * buffer, int32_t count) {
    pthread_mutex_lock(&ringbuffer_mutex);
    int32_t space = getFreeCount();
    int32_t writeCount;
    if (space == 0) {
        pthread_mutex_unlock(&ringbuffer_mutex);
        return 0;
    } else {
        writeCount = count <= space ? count : space;
    }
    int8_t * end = pBase + mLength;
    if (pRead <= pWrite) {
        int32_t w2e = end - pWrite;
        if (writeCount <= w2e) {
            memcpy(pWrite, buffer, writeCount);
            pWrite += writeCount;
            if (pWrite == end) {
                pWrite = pBase;
            }
        } else {
            memcpy(pWrite, buffer, w2e);
            memcpy(pBase, buffer + w2e, writeCount - w2e);
            pWrite = pBase + writeCount - w2e;
        }
    } else {
        memcpy(pWrite, buffer, writeCount);
        pWrite += writeCount;
    }
    pthread_cond_signal(&ringbuffer_written_cond);
    pthread_mutex_unlock(&ringbuffer_mutex);
    return writeCount;
}
mobvoi::RingBuffer::RingBuffer(int length) {
    pBase = new int8_t[length + 1];
    mLength = length + 1;
    pRead = pBase;
    pWrite = pBase;
}

mobvoi::RingBuffer::~RingBuffer() {
    delete pBase;
    pBase = NULL;
    mLength = 0;
    pRead = NULL;
    pWrite = NULL;
}

Queue

class Queue {
private:
    int MAX_SIZE;
    float * A;
    int front, rear;
public:
    // Constructor - set front and rear as -1.
    // We are assuming that for an empty Queue, both front and rear will be -1.
    Queue(int size) {
        MAX_SIZE = size;
        front = -1;
        rear = -1;
        A = new float(MAX_SIZE);
    }
    ~Queue() {
        free(A);
    }
    // To check wheter Queue is empty or not
    bool IsEmpty() {
        return (front == -1 && rear == -1);
    }

    // To check whether Queue is full or not
    bool IsFull() {
        return (rear + 1) % MAX_SIZE == front ? true : false;
    }

    // Inserts an element in queue at rear end
    void Enqueue(float x) {
        if (IsFull()) {
            //return;
            Dequeue();
        }
        if (IsEmpty()) {
            front = rear = 0;
        } else {
            rear = (rear + 1) % MAX_SIZE;
        }
        A[rear] = x;
    }

    // Removes an element in Queue from front end.
    void Dequeue() {
        if (IsEmpty()) {
            return;
        } else if (front == rear) {
            rear = front = -1;
        } else {
            front = (front + 1) % MAX_SIZE;
        }
    }
    // Returns element at front of queue.
    int Front() {
        if (front == -1) {
            //cout<<"Error: cannot return front from empty queue\n";
            return -1;
        }
        return A[front];
    }

    float getMax() {
        if (IsEmpty()) {
            return -1;
        }
        float temp = A[front];
        int count = (rear + MAX_SIZE - front) % MAX_SIZE + 1;
        //std::cout<<"Queue       : ";
        for (int i = 0; i < count; i++) {
            int index = (front + i) % MAX_SIZE; // Index of element while travesing circularly from front
            //std::cout<<A[index]<<" ";
            if (temp < A[index]) {
                temp = A[index];
            }
        }
        return temp;
    }

    /*
     Printing the elements in queue from front to rear.
     This function is only to test the code.
     This is not a standard function for Queue implementation.
     */
    void Print() {
        // Finding number of elements in queue
        int count = (rear + MAX_SIZE - front) % MAX_SIZE + 1;
        //std::cout<<"Queue       : ";
        for (int i = 0; i < count; i++) {
            int index = (front + i) % MAX_SIZE; // Index of element while travesing circularly from front
            //std::cout<<A[index]<<" ";
        }
        //std::cout<<"MAX " << getMax()<<"\n\n";
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值