VC关于子窗口中的LIST控件在主窗口中调用问题!加分++

VC关于子窗口中的LIST控件在主窗口中调用问题!加分++,第1张

list

的初始化有问题的,

你在dlg1中做个公共接口,

int

Initlist(param1,param2);

你在key中调用Dlg1Initlist()进行初始化,再显示对话框,这个方案不是很简单。。

看来你经验不够呀

WaveIn(录音)WaveHdrlpData Buffer size is FormatnAvgBytesPerSec;

WaveOut(输出)那就想多大就多大,不超过内存即可。

WaveOut:

WaveOutOpen(FWaveID, 0, @FFormat, Handle, 0, CALLBACK_WINDOW or WAVE_MAPPED); //用这个Flag

//对应的消息是:MM_WOM_DONE

//procedure WaveOutCallback(var msg: TMessage); message MM_WOM_DONE;

procedure TWaveOutWaveOutCallback(var msg: TMessage);

var

Header: PWaveHdr;

begin

Header := PWaveHdr(msgLParam);

try

if FActive then

begin

WaveOutUnPrepareHeader(FWaveID^, Header, SizeOf(TWaveHdr));

//再继续输出,就是增加输出Buffer

AutoPlayBuffer;

end;

finally

DeleteBuffer(Header); //删除/Free指针

end;

end;

这个需要去咨询相关专业的专业人员,术业有专攻。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。也可以说回调函数是应用程序提供给Windows系统DLL或其它DLL调用的函数,一般用于截获消息、获取系统信息或处理异步事件。

线程的回调函数本是一个全局或静态的函数,他不能 *** 作其他类中的数据,在线程回调函数中定义类的对象也只能使用共有成员,

如果定义一个全局的变量的话就未免没必要,

你可以这样,

你在创建线程的时候,创线程的函数中除了回调函数参数,还有另一个参数是作为传进线程里面的参数,当你需要 *** 作类中的成员,就把那他的地址做为参数,或着直接就把类的this指针做参数,这样你在回调函数中就可以直接 *** 作回调函数的参数,就是 *** 作你建线程时候给的参数,

但在回调函数中要进行强制转换,

就是你线程函数中的那个LPVOID类型的参数,用来转换。

当然,你还可以用向主窗口发送消息的方式去使主窗口的数据有改变,

比如自定消息和处理函数,在处理函数中写你需要做的事情,而这个事情是由线程来触发的,这样不就可以线程处理数据了

有许多应用程序创建的线程花费了大量时间在睡眠状态来等待事件的发生。还有一些线程进入睡眠状态后定期被唤醒以轮询工作方式来改变或者更新状态信息。线程池可以让你更有效地使用线程,它为你的应用程序提供一个由系统管理的工作者线程池。至少会有一个线程来监听放到线程池的所有等待 *** 作,当等待 *** 作完成后,线程池中将会有一个工作者线程来执行相应的回调函数。

你也可以把没有等待 *** 作的工作项目放到线程池中,用QueueUserWorkItem函数来完成这个工作,把要执行的工作项目函数通过一个参数传递给线程池。工作项目被放到线程池中后,就不能再取消了。

Timer-queue timers和Registered wait operations也使用线程池来实现。他们的回调函数也放在线程池中。你也可以用BindIOCompletionCallback函数来投递一个异步IO *** 作,在IO完成端口上,回调函数也是由线程池线程来执行。

当第一次调用QueueUserWorkItem函数或者BindIOCompletionCallback函数的时候,线程池被自动创建,或者Timer-queue timers或者Registered wait operations放入回调函数的时候,线程池也可以被创建。线程池可以创建的线程数量不限,仅受限于可用的内存,每一个线程使用默认的初始堆栈大小,运行在默认的优先级上。

线程池中有两种类型的线程:IO线程和非IO线程。IO线程等待在可告警状态,工作项目作为APC放到IO线程中。如果你的工作项目需要线程执行在可警告状态,你应该将它放到IO线程。

非IO工作者线程等待在IO完成端口上,使用非IO线程比IO线程效率更高,也就是说,只要有可能的话,尽量使用非IO线程。IO线程和非IO线程在异步IO *** 作没有完成之前都不会退出。然而,不要在非IO线程中发出需要很长时间才能完成的异步IO请求。

正确使用线程池的方法是,工作项目函数以及它将会调用到的所有函数都必须是线程池安全的。安全的函数不应该假设线程是一次性线程的或者是永久线程。一般来说,应该避免使用线程本地存储和发出需要永久线程的异步IO调用,比如说RegNotifyChangeKeyValue函数。如果需要在永久线程中执行这样的函数的话,可以给QueueUserWorkItem传递一个选项WT_EXECUTEINPERSISTENTTHREAD。

注意,线程池不能兼容COM的单线程套间(STA)模型。

为了更深入地讲解 *** 作系统实现的线程池的优越性,我们首先尝试着自己实现一个简单的线程池模型。

代码如下:

////

/// Test Our own thread pool /

////

typedef struct _THREAD_POOL

{

HANDLE QuitEvent;

HANDLE WorkItemSemaphore;

LONG WorkItemCount;

LIST_ENTRY WorkItemHeader;

CRITICAL_SECTION WorkItemLock;

LONG ThreadNum;

HANDLE ThreadsArray;

}THREAD_POOL, PTHREAD_POOL;

typedef VOID (WORK_ITEM_PROC)(PVOID Param);

typedef struct _WORK_ITEM

{

LIST_ENTRY List;

WORK_ITEM_PROC UserProc;

PVOID UserParam;

}WORK_ITEM, PWORK_ITEM;

DWORD WINAPI WorkerThread(PVOID pParam)

{

PTHREAD_POOL pThreadPool = (PTHREAD_POOL)pParam;

HANDLE Events[2];

Events[0] = pThreadPool->QuitEvent;

Events[1] = pThreadPool->WorkItemSemaphore;

for(;;)

{

DWORD dwRet = WaitForMultipleObjects(2, Events, FALSE, INFINITE);

if(dwRet == WAIT_OBJECT_0)

break;

//

// execute user's proc

//

else if(dwRet == WAIT_OBJECT_0 +1)

{

PWORK_ITEM pWorkItem;

PLIST_ENTRY pList;

EnterCriticalSection(&pThreadPool->WorkItemLock);

_ASSERT(!IsListEmpty(&pThreadPool->WorkItemHeader));

pList = RemoveHeadList(&pThreadPool->WorkItemHeader);

LeaveCriticalSection(&pThreadPool->WorkItemLock);

pWorkItem = CONTAINING_RECORD(pList, WORK_ITEM, List);

pWorkItem->UserProc(pWorkItem->UserParam);

InterlockedDecrement(&pThreadPool->WorkItemCount);

free(pWorkItem);

}

else

{

_ASSERT(0);

break;

}

}

return 0;

}

BOOL InitializeThreadPool(PTHREAD_POOL pThreadPool, LONG ThreadNum)

{

pThreadPool->QuitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

pThreadPool->WorkItemSemaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);

pThreadPool->WorkItemCount = 0;

InitializeListHead(&pThreadPool->WorkItemHeader);

InitializeCriticalSection(&pThreadPool->WorkItemLock);

pThreadPool->ThreadNum = ThreadNum;

pThreadPool->ThreadsArray = (HANDLE)malloc(sizeof(HANDLE) ThreadNum);

for(int i=0; i<ThreadNum; i++)

{

pThreadPool->ThreadsArray[i] = CreateThread(NULL, 0, WorkerThread, pThreadPool, 0, NULL);

}

return TRUE;

}

VOID DestroyThreadPool(PTHREAD_POOL pThreadPool)

{

SetEvent(pThreadPool->QuitEvent);

for(int i=0; i<pThreadPool->ThreadNum; i++)

{

WaitForSingleObject(pThreadPool->ThreadsArray[i], INFINITE);

CloseHandle(pThreadPool->ThreadsArray[i]);

}

free(pThreadPool->ThreadsArray);

CloseHandle(pThreadPool->QuitEvent);

CloseHandle(pThreadPool->WorkItemSemaphore);

DeleteCriticalSection(&pThreadPool->WorkItemLock);

while(!IsListEmpty(&pThreadPool->WorkItemHeader))

{

PWORK_ITEM pWorkItem;

PLIST_ENTRY pList;

pList = RemoveHeadList(&pThreadPool->WorkItemHeader);

pWorkItem = CONTAINING_RECORD(pList, WORK_ITEM, List);

free(pWorkItem);

}

}

BOOL PostWorkItem(PTHREAD_POOL pThreadPool, WORK_ITEM_PROC UserProc, PVOID UserParam)

{

PWORK_ITEM pWorkItem = (PWORK_ITEM)malloc(sizeof(WORK_ITEM));

if(pWorkItem == NULL)

return FALSE;

pWorkItem->UserProc = UserProc;

pWorkItem->UserParam = UserParam;

EnterCriticalSection(&pThreadPool->WorkItemLock);

InsertTailList(&pThreadPool->WorkItemHeader, &pWorkItem->List);

LeaveCriticalSection(&pThreadPool->WorkItemLock);

InterlockedIncrement(&pThreadPool->WorkItemCount);

ReleaseSemaphore(pThreadPool->WorkItemSemaphore, 1, NULL);

return TRUE;

}

VOID UserProc1(PVOID dwParam)

{

WorkItem(dwParam);

}

void TestSimpleThreadPool(BOOL bWaitMode, LONG ThreadNum)

{

THREAD_POOL ThreadPool;

InitializeThreadPool(&ThreadPool, ThreadNum);

CompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

BeginTime = GetTickCount();

ItemCount = 20;

for(int i=0; i<20; i++)

{

PostWorkItem(&ThreadPool, UserProc1, (PVOID)bWaitMode);

}

WaitForSingleObject(CompleteEvent, INFINITE);

CloseHandle(CompleteEvent);

DestroyThreadPool(&ThreadPool);

}

我们把工作项目放到一个队列中,用一个信号量通知线程池,线程池中任意一个线程取出工作项目来执行,执行完毕之后,线程返回线程池,继续等待新的工作项目。

线程池中线程的数量是固定的,预先创建好的,永久的线程,直到销毁线程池的时候,这些线程才会被销毁。

线程池中线程获得工作项目的机会是均等的,随机的,并没有特别的方式保证哪一个线程具有特殊的优先获得工作项目的机会。

而且,同一时刻可以并发运行的线程数目没有任何限定。事实上,在我们的执行计算任务的演示代码中,所有的线程都并发执行。

下面,我们再来看一下,完成同样的任务,系统提供的线程池是如何运作的。

////

/// QueueWorkItem Test /

////

DWORD BeginTime;

LONG ItemCount;

HANDLE CompleteEvent;

int compute()

{

srand(BeginTime);

for(int i=0; i<20 1000 1000; i++)

rand();

return rand();

}

DWORD WINAPI WorkItem(LPVOID lpParameter)

{

BOOL bWaitMode = (BOOL)lpParameter;

if(bWaitMode)

Sleep(1000);

else

compute();

if(InterlockedDecrement(&ItemCount) == 0)

{

printf("Time total %d second\n", GetTickCount() - BeginTime);

SetEvent(CompleteEvent);

}

return 0;

}

void TestWorkItem(BOOL bWaitMode, DWORD Flag)

{

CompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

BeginTime = GetTickCount();

ItemCount = 20;

for(int i=0; i<20; i++)

{

QueueUserWorkItem(WorkItem, (PVOID)bWaitMode, Flag);

}

WaitForSingleObject(CompleteEvent, INFINITE);

CloseHandle(CompleteEvent);

}

很简单,是吧?我们仅需要关注于我们的回调函数即可。但是与我们的简单模拟来比,系统提供的线程池有着更多的优点。

首先,线程池中线程的数目是动态调整的,其次,线程池利用IO完成端口的特性,它可以限制并发运行的线程数目,默认情况下,将会限制为CPU的数目,这可以减少线程切换。它挑选最近执行过的线程再次投入执行,从而避免了不必要的线程切换。

sleep()函数引起的休眠状态无法被唤醒,除非休眠时间到。或者线程被强制终止。

如果想实现休眠功能,应该用线程挂起,在线程中获得指向自身的线程指针,用SuspendThread()函数来挂起线程,用ResumeThread()函数来唤醒。

举例如下:

在CDriver类中声明了一个句柄CWinThread pThread; 最好为公有变量。

在CDriver类中新建一个线程

pThread=::AfxBeginThread(::CallbackThread,this,THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED,NULL); // CallbackThread为工作者线程的回调函数,将CDriver对象的自身指针this作为参数传递给回调函数

m_hEventThrdQuit=CreateEvent(NULL,TRUE,FALSE,_T("ThreadQuit")); // 产生一个用于控制线程退出的事件,也是公有变量

ASSERT(m_hEventThrdQuit);

//

pThread->ResumeThread(); // 唤醒线程让其执行

在回调函数中,通过初始化参数获得CDriver的指针

UINT AFX_CDECL CallbackThread(LPVOID pParam)

{

CDriver pDriver=NULL;

pDriver=(CDriver)pParam;

ASSERT(pDriver);

while (WaitForSingleObject(pDriver->m_hEventThrdQuit,0)!=WAIT_OBJECT_0)

{

// 加入自己的实现代码

pDriver->pThread->SuspendThread(); // 执行完任务后挂起线程实现休眠

}

// 线程退出

pDriver=NULL;

::AfxEndThread(0);

return 0;

}

在CDriver类中,需要唤醒线程时调用pThread->ResumeThread();即可,该线程执行完一轮任务后自动挂起。

需要退出线程时,调用::SetEvent(m_hEventThrdQuit);线程会自己退出的。

我也在研究这个 不过至少你以前用回调函数做过了 我才初学 刚刚看了个用线程的发给你吧

也不一定能帮到您

http://wenkubaiducom/view/6f804c360b4c2e3f572763a5html

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/12157682.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-21
下一篇2023-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存