多线程同步队列
0x01 程序结构
将多线程同步队列实现为类,对外提供以下接口:
- get()
- put()
类内部维护三个句柄用于同步:
- full信号量表示是否可读
- empty信号量表示是否可写
- buffer_mutex互斥对象用于同步对缓冲区的操作
队列中保存指针,这样可实现保存多种类型的对象。
0x02 代码
multithreadedqueue.h
#ifndef ____MULTITHREADEDQUEUE____H____
#define ____MULTITHREADEDQUEUE____H____
#include <windows.h>
typedef unsigned long * pointer32;
class queue
{
pointer32 * buffer;
int first;
int last;
int buffer_len;
HANDLE full;
HANDLE empty;
HANDLE buffer_mutex;
public:
queue(int len = 5);
void put(pointer32 element);
pointer32 get();
~queue();
};
#endif
multithreadedqueue.cpp
#include "multithreadedqueue.h"
#include <Windows.h>
#define TEST
#ifdef TEST
#include <stdio.h>
#endif
queue::queue(int len)
{
buffer_len = len;
buffer = new pointer32 [buffer_len];
first = 0;
last = 0;
full = CreateSemaphore(NULL, 0, buffer_len-1, NULL);
empty = CreateSemaphore(NULL, buffer_len-1, buffer_len-1, NULL);
buffer_mutex = CreateMutex(NULL, FALSE, NULL);
}
pointer32 queue::get()
{
pointer32 ret;
WaitForSingleObject(full, INFINITE);
WaitForSingleObject(buffer_mutex, INFINITE);
ret = *(buffer + first);
first = (first + 1) % buffer_len;
#ifdef TEST
printf("consumer no.%d: value is %d, addr is 0x%08u\n", GetCurrentThreadId(), *(int*)ret, ret);
Sleep(100);
#endif // TEST
ReleaseMutex(buffer_mutex);
ReleaseSemaphore(empty, 1, NULL);
return ret;
}
void queue::put(pointer32 element)
{
WaitForSingleObject(empty, INFINITE);
WaitForSingleObject(buffer_mutex, INFINITE);
*(buffer + last) = element;
last = (last + 1) % buffer_len;
#ifdef TEST
printf("producer no.%d: value is %d, addr is 0x%08u\n", GetCurrentThreadId(), *(int*)element, element);
Sleep(100);
#endif // TEST
ReleaseMutex(buffer_mutex);
ReleaseSemaphore(full, 1, NULL);
}
queue::~queue()
{
CloseHandle(full);
CloseHandle(empty);
CloseHandle(buffer_mutex);
delete [] buffer;
}
0x03 测试
test.cpp
#include <windows.h>
#include "multithreadedqueue.h"
#include <stdio.h>
queue q;
DWORD WINAPI Producer(PVOID pvParam)
{
while (1)
{
q.put((pointer32)new int(rand()));
}
return 0;
}
DWORD WINAPI Consumer(PVOID pvParam)
{
pointer32 value;
while (1)
{
value = q.get();
delete value;
}
return 0;
}
int main()
{
HANDLE hThread;
DWORD thread_id;
DWORD producer_count, consumer_count, exec_time;
printf("producer_count, consumer_count, exec_time:\n");
scanf("%u %u %u", &producer_count, &consumer_count, &exec_time);
while (producer_count--)
{
hThread = CreateThread(NULL, 0, Producer, NULL, 0, &thread_id);
CloseHandle(hThread);
}
while (consumer_count--)
{
hThread = CreateThread(NULL, 0, Consumer, NULL, 0, &thread_id);
CloseHandle(hThread);
}
Sleep(exec_time);
return 0;
}
测试用例1: 1生产者,1消费者,运行1秒
测试用例2: 1生产者,4消费者,运行3秒
测试用例3: 4生产者,1消费者,运行3秒
测试用例4: 4生产者,4消费者,运行5秒
输出中的value为生成对象的值,addr为地址。值一样时用地址区分存入 队列的对象。