队列与两个不同的锁同时发生:一个用于enqueue()以保护同时排队的多个线程&一个用于dequeue()获得相同的效果。
如果队列已满,则添加(入队)只是跳过(返回)插入。 如果队列为空,则Remove(dequeue)会跳过删除。
我使用doRandom()生成0到1之间的一堆随机数。我使用这些数字来决定是否添加/删除。
性能:我尝试使用静态/动态线程分配来测试队列。对于两种分配算法,> 1个线程的执行时间明显较慢。
//g++ -std=c++0x -pthread -o block blocking.cpp;./block
#include <iostream>
#include <thread>
#include <mutex>
#include <atomic>
#include <random>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <ctime>
#include <condition_variable>
using namespace std;
#define NUMBER_OF_THREADS 1
#define NUMBER_OF_OPERATIONS 10000000
#define QUEUE_CAPACITY 1000000
std::vector<double> getRandom();
template <class T> class BoundedQueue {
private:
T * array;
int head, tail, capacity;
std::mutex enqLock, deqLock;
std::atomic<long> sharedCounter;
std::condition_variable notEmptyCondition, notFullCondition;
public:
void staticAllocation(double randomNumbers[], int threadID);
void dynamicAllocation(double randomNumbers[]);
void add (T x);
BoundedQueue ();
void remove ();
};
template <class T> BoundedQueue<T>::BoundedQueue () {
capacity = QUEUE_CAPACITY;
array = new T[capacity];
head = 0;
tail = 0;
sharedCounter = 0;
}
template <class T> void BoundedQueue<T>::add (T x) {
enqLock.lock();
if (tail - head == capacity) {
enqLock.unlock();
return;
}
array[tail % capacity] = x;
tail++;
enqLock.unlock();
}
template <class T> void BoundedQueue<T>::remove() {
deqLock.lock();
if (tail - head == 0) {
deqLock.unlock();
return;
}
T result = array [head % capacity];
head++;
deqLock.unlock();
}
template <class T> void BoundedQueue<T>::dynamicAllocation(double randomNumbers[]) {
long i = 0;
while (i < QUEUE_CAPACITY) {
i = sharedCounter.fetch_add(1, std::memory_order_relaxed);
if(randomNumbers[i] <= 0.5) add(0);
else remove();
}
}
template <class T> void BoundedQueue<T>::staticAllocation (double randomNumbers[], int threadID) {
int split = NUMBER_OF_OPERATIONS / NUMBER_OF_THREADS;
for (int i = threadID * split; i < (threadID * split) + split; i++) {
if(randomNumbers[i] <= 0.5) add(0);
else remove();
}
}
std::vector<double> getRandom() {
std::vector<double> numbers;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0,1);
for(int i = 0; i < NUMBER_OF_OPERATIONS; i++) numbers.push_back(dis(gen));
return numbers;
}
int main () {
BoundedQueue<int> bQ;
std::vector<double> temp = getRandom();
double* randomNumbers = &temp[0];
std::thread myThreads[NUMBER_OF_THREADS];
clock_t begin = clock();
for(int i = 0; i < NUMBER_OF_THREADS; i++) {
myThreads[i] = std::thread ( [&] {bQ.dynamicAllocation(randomNumbers); });
}
for(int i = 0; i < NUMBER_OF_THREADS; i++) {
if(myThreads[i].joinable()) myThreads[i].join();
}
clock_t end = clock();
cout << double(end-begin) * 1000 / CLOCKS_PER_SEC;
return 0;
}
答案 0 :(得分:0)
这里没有并行性。请注意,所有线程几乎都会被序列化,因为您在函数的开头锁定并在结束时释放它。
虽然由于缺乏并行性而在线程之间划分工作,但锁定/解锁的开销占主导地位,并且整体显示与单线程相比较大的执行时间。
所以并发性但是没有并行性,我们只需支付同步价格而没有性能优势。