|
发表于 2012-12-12 15:55:10
|
显示全部楼层
mcuprogram 发表于 2012-12-11 22:20 
有例子吗?
多线程可以用来保证线程挂起时不影响其它的操作。这是我的USB转HDMI的发包例子,
bool DaemonExit = false;
void CLVDSDDlg::OnBnClickedBtnStart()
{
// TODO: Add your control notification handler code here
if(!hDaemon)
CreateDaemon();
}
void CLVDSDDlg::OnBnClickedBtnStop()
{
// TODO: Add your control notification handler code here
if(!hDaemon)
return;
DaemonExit = true;
WaitForSingleObject(hDaemon,INFINITE);
DaemonExit = false;
hDaemon = NULL;
dDaemon = 0;
}
#define WIDTH 1920
#define HEIGHT 1080
BYTE * pScreenBuffer = new BYTE[WIDTH*HEIGHT*2];
//BYTE * pNewScreenBuffer = new BYTE[WIDTH*HEIGHT*2];
BYTE * pUSBBuffer = new BYTE[65536-32];
struct BufferQueue
{
BYTE * data;
long length;
BufferQueue * next;
BufferQueue()
{
data = NULL;
next = NULL;
length = 0;
}
};
struct BufferWriteThread
{
BYTE ** Queue;
int StartIndex;
int EndIndex;
CCyUSBDevice *USBDevice;
};
BufferQueue * Head = new BufferQueue();
BufferQueue * cursor = Head;
int BufferCount = 0;
HANDLE hLockBufferCount = CreateMutex(NULL,FALSE,NULL);
#define AddCounterThreashold 16
#define RemoveCounterThreashold 36
void RefreshBuffer()
{
CCyUSBDevice *USBDevice = new CCyUSBDevice(NULL);
while(true)
{
BYTE * Data = NULL;
long Length = 0;
WaitForSingleObject(hLockBufferCount,INFINITE);
if(Head->next)
{
Data = Head->data;
Length = Head->length;
BufferQueue * tmp = Head;
Head = Head->next;
delete tmp;
}
BufferCount--;
ReleaseMutex(hLockBufferCount);
if(Data == NULL)
Sleep(15);
else
{
// Write data
USBDevice->BulkOutEndPt->XferData(Data, Length, NULL, false);
// Delete buffer
delete []Data;
}
if(DaemonExit)
break;
}
USBDevice->Close();
}
#define THCNT 4
HANDLE ThreadsWriteUSB[THCNT] = {0};
DWORD ThreadsIDWriteUSB[THCNT] = {0};
void Daemon()
{
VIDEODRIVER * videoDrv = new VIDEODRIVER();
DWORD LastErr = 0;
videoDrv->VIDEODRIVER_start(0,0,WIDTH,HEIGHT,16);
if(!videoDrv->mypVideoMemory)
{
LastErr = GetLastError();
MessageBox(NULL,"Error opening device.","Error opening device.",1);
return;
}
if(!videoDrv->HardwareCursor())
{
LastErr = GetLastError();
}
// Monitors screen change. Color depth MUST be 16 bits
int Count = 0;
int StartPt = 0;
while(true)
{
int BufferIndex = 0;
//int PixelIndex = 0;
PCHAR pNewScreenBuffer = videoDrv->myframebuffer;
int FrameRefreshCount = 0;
StartPt = WIDTH * 2 - StartPt;
for(int ScreenPt = 0; ScreenPt < WIDTH * HEIGHT * 2; ScreenPt +=8)
{
if(*((__int64 *)(&pScreenBuffer[ScreenPt])) != *((__int64 *)(&pNewScreenBuffer[ScreenPt])))
{
ScreenPt &= 0xFFFFFFF0;
*((unsigned short *)(&pUSBBuffer[BufferIndex]))=0x8007;
// Note the buffer is byte-addressable thus the address is byte address.
*((unsigned int *)(&pUSBBuffer[BufferIndex+2]))=ScreenPt;
*((unsigned __int64 *)(&pUSBBuffer[BufferIndex+6])) = *((unsigned __int64 *)(&pNewScreenBuffer[ScreenPt]));
*((__int64 *)(&pScreenBuffer[ScreenPt])) = *((__int64 *)(&pNewScreenBuffer[ScreenPt]));
ScreenPt += 8;
*((unsigned __int64 *)(&pUSBBuffer[BufferIndex+14])) = *((unsigned __int64 *)(&pNewScreenBuffer[ScreenPt]));
*((__int64 *)(&pScreenBuffer[ScreenPt])) = *((__int64 *)(&pNewScreenBuffer[ScreenPt]));
BufferIndex += 32;
if(BufferIndex == 65536-32)
{
// Add Buffer
cursor->data = pUSBBuffer;
cursor->length = 65536-32;
pUSBBuffer = new BYTE[65536-32];
cursor->next = new BufferQueue();
cursor = cursor->next;
//long length = 65536-32;
//USBDevice->BulkOutEndPt->XferData(pUSBBuffer, length, NULL, false);
BufferIndex = 0;
Count++;
if(Count == AddCounterThreashold)
{
WaitForSingleObject(hLockBufferCount,INFINITE);
BufferCount+=Count;
Count = 0;
ReleaseMutex(hLockBufferCount);
}
while(BufferCount >= RemoveCounterThreashold)
Sleep(15);
FrameRefreshCount++;
}
}
}
if(BufferIndex > 0)
{
cursor->data = pUSBBuffer;
cursor->length = BufferIndex;
pUSBBuffer = new BYTE[65536-32];
cursor->next = new BufferQueue();
cursor = cursor->next;
//long length = 65536-32;
//USBDevice->BulkOutEndPt->XferData(pUSBBuffer, length, NULL, false);
BufferIndex = 0;
Count++;
if(Count == AddCounterThreashold)
{
WaitForSingleObject(hLockBufferCount,INFINITE);
BufferCount+=Count;
Count = 0;
ReleaseMutex(hLockBufferCount);
}
while(BufferCount >= RemoveCounterThreashold)
Sleep(15);
FrameRefreshCount++;
}
if(DaemonExit)
break;
if(FrameRefreshCount < AddCounterThreashold)
Sleep(15);
}
videoDrv->VIDEODRIVER_Stop();
}
void CLVDSDDlg::CreateDaemon()
{
if(ThreadsWriteUSB[0] == 0)
{
// Create Buffer Write daemon
for(int i=0; i<THCNT; i++)
{
ThreadsWriteUSB = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RefreshBuffer,NULL,CREATE_SUSPENDED,&ThreadsIDWriteUSB);
SetThreadPriority(ThreadsWriteUSB,THREAD_PRIORITY_ABOVE_NORMAL);
ResumeThread(ThreadsWriteUSB);
}
}
hDaemon = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Daemon,NULL,CREATE_SUSPENDED,&dDaemon);
SetThreadPriority(hDaemon,THREAD_PRIORITY_NORMAL);
ResumeThread(hDaemon);
}
void CLVDSDDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
DaemonExit = true;
CDialog::OnClose();
}
注意这不是USB显卡,而是用MirrorDriver把显示缓冲刷到FPGA板上面。
开始用的是单线程,速度奇慢,跟放幻灯片一样,然后改成全多线程,现在相当流畅了(新台机上能达到几乎无停顿的效果,老机上刷屏时比较卡)。
MirrorDriver用的是UVNC的。
其实多线程的目的,一是让一个线程不影响另一个线程,二是使用线程,同步更方便,更容易并行化。所谓GPU运算速度快,实质是GPU由几百上千个运算单元同时并行运算,速度自然就上去了。多线程程序也如此。只不过受限于USB2的速度,最大可达速度为50MB/s左右。 |
|