|
As far as I can tell from what you've posted, the extra thread is unnecessary.
Any time you need to pick an arbitrary timeout that "should" be the right amount of time,
there's probably something flawed in the design.
I can't tell what's going on since there's missing code (at least one curly bracket is
missing from the thread proc).
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
since i need to continuous output the position of sliders while i can STILL change the drag the sliders, i definitedly need a worker thread.
the basic idea is that i have a dialog with 4 sliders, a start button and a stop button. when start button clicked, a worker threads starts output the current position of the sliders, and stop when stop button clicked.
here's a more complete code:
in CMy61xxMTDlg.h:
//define user message
#define WM_USER_GET_DATA WM_USER+0x100
#define WM_USER_THREAD_ABORTED WM_USER+0x101
//define thread function
UINT ThreadFunc(LPVOID pParam);
//define thread function parameter
typedef struct tagTHREADPARMS {
CWnd* pWnd;
CEvent* pKillEvent;
CEvent* pOutputEvent;
class CMy61xxMTDlg* pDlg;
} THREADPARMS;
class CMy61xxMTDlg : public CDialog
{.....
afx_msg LRESULT OnGetData(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnThreadAborted(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
.....
HANDLE m_hThread;
CEvent m_KillEvent;
CEvent m_OutputEvent;
void GetData(char* pbyData, int32 lBufsize);
void ThreadAborted();
......
}
in CMy61xxMTDlg.cpp:
BEGIN_MESSAGE_MAP(CMy61xxMTDlg, CDialog)
......
//user defined message handler
ON_MESSAGE (WM_USER_GET_DATA, OnGetData)
ON_MESSAGE (WM_USER_THREAD_ABORTED, OnThreadAborted)
END_MESSAGE_MAP()
void CMy61xxMTDlg::OnBnClickedButtonStart()
{
// TODO: Add your control notification handler code here
THREADPARMS*ptp=new THREADPARMS;
ptp->pDlg=this;
ptp->pWnd=AfxGetMainWnd();
ptp->pKillEvent=&m_KillEvent;
ptp->pOutputEvent=&m_OutputEvent;
CWinThread* pThread=AfxBeginThread( ThreadFunc,ptp,-1,0,CREATE_SUSPENDED);
::DuplicateHandle(.....)
m_OutputEvent.SetEvent();
pThread->ResumeThread();
}
void CMy61xxMTDlg::OnBnClickedButtonStop()
{
// TODO: Add your control notification handler code here
//Stop thread
m_KillEvent.SetEvent();
}
UINT ThreadFunc(LPVOID pParam)
{
THREADPARMS*ptp=(THREADPARMS*)pParam;
CWnd*pWnd=ptp->pWnd;
CMy61xxMTDlg*pDlg=ptp->pDlg;
CEvent* pKillEvent=ptp->pKillEvent;
CEvent* pOutputEvent=ptp->pOutputEvent;
delete ptp;
pWnd->PostMessageW(WM_USER_GET_DATA,0,0);
while(::WaitForSingleObject(pOutputEvent->m_hObject,0)==WAIT_OBJECT_0 && pDlg->nErr==ERR_OK)
{
pDlg->m_OutputEvent.ResetEvent();
SpcSetParam (pDlg->hDrv, SPC_FIFO_BUFREADY, pDlg-> nBufIdx);//some external library function, transfer data to a hardware and output
pWnd->PostMessageW(WM_USER_GET_DATA,0,0);
if(::WaitForSingleObject(pKillEvent->m_hObject,0)==WAIT_OBJECT_0)
{
pWnd->PostMessageW(WM_USER_THREAD_ABORTED);
return -1;
}
}
return 0;
}
LRESULT CMy61xxMTDlg::OnGetData(WPARAM wParam, LPARAM lParam){
CMy61xxMTDlg*pDlg=(CMy61xxMTDlg *) GetActiveWindow();
if(pDlg!=NULL)
pDlg->GetData(pbyData[nBufIdx], BUFSIZE);
return 0;
}
LRESULT CMy61xxMTDlg::OnThreadAborted(WPARAM wParam, LPARAM lParam){
CMy61xxMTDlg*pDlg=(CMy61xxMTDlg *) GetActiveWindow();
if(pDlg!=NULL)
pDlg->ThreadAborted();
return 0;
}
void CMy61xxMTDlg::GetData(ptr8 pbyData, int32 lBufsize)
{
int i;
for (i=0; i<BUFSIZE; i ++)
{
pbyData[i]=(int8)m_Slider_Data[i].GetPos();
}
m_OutputEvent.SetEvent();
}
hope the code is clear this time, the problem is that the while loop in the thread function only run once....
-- modified at 17:08 Friday 10th August, 2007
|
|
|
|
|
There's still a missing curly brace in ThreadFunc
You're showing a while loop with the closing brace after the return 0.
What's the reason for the thread? Does SpcSetParam take a long time to output?
As it is right now, you're just looping in the thread, outputting values as fast as you can get them.
And you're using the UI thread to get those values
This will hurt your UI more than not using a thread!
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
yes, i am using the UI thread to get the position of sliders in UI thread, because i can't do that in the worker thread directly.
the while loop is waiting for the m_OutputEvent to be signaled, once signaled, and then immediately the event is reset in the loop, so next time, the while loop is blocked until is event is signaled again.
in the while loop i post a message to run GetData() function to get slider positions from UI thread,once this done, i signaled m_OutputEvent so the while loop is unblocked.
so the basic mechanism is:
data ready-> signal m_OutputEvent, unblock while loop->reset m_outputEvent->run SpcSetParam() function to output data->post message->run GetData() function->data ready-> signal m_OutputEvent..... and goes on
i did this to prevent that the SpcGetParam run before the data is ready.
|
|
|
|
|
Right, got all that. You're avoiding my questions though
Worker thread waits on the event
(Assuming the event is set within 1000ms the first time around...)
Worker thread resets event
Worker thread calls SpcSetParam
Worker thread posts the message.
UI thread gets the message, gets the data, sets the event.
Loop
Unless SpcSetParam takes alot of time, you're posting alot of events to the ui thread per second.
If SpcSetParam needs continuous input, regardless of changes to the sliders, that's one thing.
If SpcSetParam doesn't need to be called unless a slider position changes, then it would be WAY
more efficient to make it event driven - just call SpcSetParam whenever a slider changes.
Again, as it looks now, you're getting little-to-no benefit from the extra thread.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
ok, the hardware i'm using is a analog signal generator, and i monitor the signal on the oscilloscope.
the sliders are used to change the signal output.
the hardware come with its own library functions, which is the SpcSetParam().it sets the hardware to run in FIFO mode, a typical mode for continuous data output.
the SpcSetParam get the data from a software buffer, in this case, my data array contain slider positions,pass it to hardware buffer, then the data in hardware buffer is outputed and i can see it on the oscilloscope.
i want to see the output continously, it can't just run it once and gone, that's why i'm looping.
SpcGetParam() does not take long since the hardware processing speed is 100MB/s.
SpcGetParam() just take the data buffer contain the slider position, so the output doesn't reflect on immediate change of sliders, since looping is fast, the effect is almost immediate.
|
|
|
|
|
I agree with Mark, event driven is definitely the way to go.
Option 1:
declare pbyData[] as an array of volatile values
use OnHScroll & OnVScroll to update the pbyData[] values when slider positions change
Add a pointer value (assigned to pbyData) as one of the members of THREADPARMS
Then you only have to check for the kill event in your worker thread.
Only one event to monitor which is only ever set from the main thread, no deadlocks.
NOTE: Without a SwitchToThread() call in the worker thread loop, this approach will kill your interface responsiveness (& your O/S responsiveness without a multicore CPU!). If you're thinking of a Sleep(...) call, you might as well use a timer...
Option 2:
use OnHScroll & OnVScroll to update the pbyData[] values when slider positions change
Set a timer (delay value depending on exactly what you mean by "continuously output")
Call SpcGetParam() in OnTimer()
No threads, no deadlocks.
T-Mac-Oz
|
|
|
|
|
hi, T-Mac, thx for the reply. I'm not sure if you familiar with the First in,First out(FIFO) mode,the hardware use the fifo mode and the function, SpcGetParam(), i can't change it.
the ScpGetParam function just take a chunk of data in the software data buffer and store the content to onboard hardware buffer, wut if i'm trying to write data into pbyData[] in OnVScroll() while SpcGetParam() try to reads it?
the SpcGetParam() could be running at 100Hz, i really don't think using a timer is such a good idea.
the thing i'm trying to do is like changing the output anytime and the data is outputing contiunously and endlessly, and i can monitor the output on oscilloscope in real time.
i really don't have any better idea other than running a worker thread and using message to tell the main thread to store the data. if someone have any better way to do it, please do tell me
|
|
|
|
|
Hi Albert,
After having another look at your original posted code, it seems you are using threads to perform what is essentially a sequential task!
Worker thread posts WM_USER_GET_DATA
Main thread receives WM_USER_GET_DATA*
Main thread calculates output
Main thread signals "output" event
Worker thread receives "output" event
Worker thread outputs data
Worker thread posts WM_USER_GET_DATA
Main thread receives WM_USER_GET_DATA*
Main thread calculates output
Main thread signal "output" event
Worker thread receives ...
* Yes, the main thread is processing other messages but given that the WM_USER_GET_DATA is sent to the main thread using PostMessage(...), the worker thread ends up having to wait on processing of other messages before its WM_USER_GET_DATA message is processed anyway!
A much cleaner solution that accomplishes exactly the same thing is:
#define WM_USER_GET_DATA WM_USER+0x100
class CMy61xxMTDlg : public CDialog
{
.....
bool m_bDoOutput;
afx_msg LRESULT OnGetData(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnUserStop(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
.....
void OnUserGetData();
void OnBnClickedButtonStart()
{
m_bDoOutput = true;
PostMessage(WM_USER_GET_DATA);
};
void OnBnClickedButtonStop() { m_bDoOutput = false; };
.....
}
......
BEGIN_MESSAGE_MAP(CMy61xxMTDlg, CDialog)
......
ON_MESSAGE (WM_USER_GET_DATA, OnUserGetData)
......
END_MESSAGE_MAP()
void CMy61xxMTDlg::OnUserGetData()
{
if (!m_bDoOutput)
return;
ptr8 pbyData;
for (i=0; i<BUFSIZE; i ++)
{
pbyData[i]=(int8)m_Slider_Data[i].GetPos();
}
SpcSetParam(...);
PostMessage(WM_USER_GET_DATA);
}
Threads are great for their intended purpose, which is to permit semi-independent operations to execute in parallel.
The tight looping and total dependence on event signals should have tipped me off right away that what you were trying to achieve was not really parallel processing at all.
As you've already found out, threads and thread synchronisation are tricky beasts, so it's always worth exploring alternative implementations (such as timers and/or user message events) before resorting to a multi-threaded solution to a problem.
Threading sounds cool & it is cool but don't leap into trying to use threads just because you think you can, you will most often come up with a sub-optimal solution.
BTW. I do understand the FIFO concept & that is precisely why using a timer is a better idea than continually looping in a background thread (or perhaps even the self-propagating event solution above).
If, as you say, SpcGetParam(...) adds the supplied data in the on-board hardware buffer (i.e. the end of the FIFO queue), then a system running at 2Gz (forget FSB, the small volume of data we're talking about here can almost be guaranteed to always be cached), with the other minimal processing involved, feeding a FIFO queue being read at 100MHz will sooner or later (probably sooner) fill & overflow (or maybe wrap around, or block, or drop values, depends on the firmware) the hardware buffer. Using a timer gives you the opportunity to match your output frequency to the oscilloscope frequency. If the standard system timer resolution is not fine-grained enough for you, there are other timers available in windows, search Code Project for "timers" & you'll find plenty of articles. If you insist on using threads, protecting access to m_pbyData[] as a member of CMy61xxMTDlg is easily accomplished using mutexes.
Regards,
T-Mac-Oz
|
|
|
|
|
It's very hard to differentiate between your code snippets and the actual text. Please revise your post by surrounding the code snippets with <pre> tags. Then, before committing the post, preview it to make sure everything is as you expect it to be (e.g., angle brackets).
"A good athlete is the result of a good and worthy opponent." - David Crow
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
|
|
|
|
|
How do I go about displaying JPG/GIF images?
Simon Smith
|
|
|
|
|
One way is to read the file and convert to a device independent bitmap or a device dependent bitmap
and use GDI to render the image.
GDI+ can do the loading and drawing for you in a few simple steps.
ATL has the CImage class which will do it as well.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thank you for your responce
I am very new to visual c++, so I dont know what the gdi+
or the ATL is
What I am trying to do is to try out some imaging processing, so i'll need it in the raw form.
I belive visual has the facility to get the pixel attributes
Is it possible to load the image to the screen and get
the approbiate values from this kind of method?
Thanks very much
Simon Smith
simon smith
|
|
|
|
|
I would say the CImage class would be an easy place to start and be able to work with images right away.
Before I try putting some sample code here -
Are you using MFC or straight Win32?
Do you have basic Windows programming skills as far as windowing, messages, etc?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I am learning visuall c++ again, I learnt it about 8 years
ago from a book from wrox.
so some stuff makes sense, but I am going through the book again.
I am useing mfc and I have basic progframing skills
(loops, ifs, pointers)
regarding windows programing skills, Once I have gone through the book again, I can then only tell you how I am
at it.
Can you recommend any books or websites that I can further
develop my skills.
If you have any source code suitable for me regarding the imaging or anything that would be great
from my understanding so far, I have created a single document mfc application. Do I add theb Cimage class the same as the virtual functions?
cheers Simon
the virtual functions, this is an area I am stuck on
simon
|
|
|
|
|
Hi simon,
I wizarded together an SDI application that loads tiff/bmp/jpeg/gif files as a CImage.
I'll email it to you.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Simple way is:
#include "AtlImage.h"
CImage m_Image;
m_Image.Load("c:\\yourfile.jpg");
e.BitBlt(dc->m_hdc,800,600);
m_Image.Detach();
|
|
|
|
|
Do you have any sample code that demonstrates this,
I am a begginer and I'm not sure how this fits in
|
|
|
|
|
I have the exact image of a .bmp file in memory, loaded from a database. How can I create a valid CBitmap from it and get it to print?
I can load the .bmp file locally using LoadImage(...LR_LOADFROMFILE...), which returns a valid HBITMAP handle, and it prints fine. But when I use CreateBitmap() et al. and try to load the instance with the in-memory bitmap info from BITMAPFILEHEADER and BITMAPINFOHEADER (width, height, planes etc.) it fails when I try to SelectObject() into a temporary DC.
How can I duplicate all of the functions of LoadImage() when the source is neither a resource nor an actual file, but rather an image of the .bmp file in memory? The goal is to end up with a valid HBITMAP handle that can then be Selected into a DC and printed.
Does anyone have any code examples for this kind of operation?
Thanks.
|
|
|
|
|
You could use CreateDIBSection() to create the HBITMAP then copy the pixel bits to the
DIB section.
BITMAPFILEHEADER *pBitmapFileHeader = (BITMAPFILEHEADER*)pFileBytesInMemory;
BITMAPINFO *pBitmapInfo = (BITMAPINFO*)((BYTE*)pFileBytesInMemory + sizeof(BITMAPFILEHEADER));
BYTE *pBitmapBits = 0;
HBITMAP hBitmap = ::CreateDIBSection(NULL, pBitmapInfo, DIB_RGB_COLORS, &pBitmapBits, NULL, 0);
if (hBitmap)
{
memcpy(pBitmapBits, (BYTE*)pFileBytesInMemory + pBitmapFileHeader->bfOffBits, pBitmapInfo->bmiHeader.biSizeImage);
...
}
Mark
.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark,
Thank you, thank you, thank you! It worked beautifully the first time.
I wish the documentation was easier to plod through to find simple solutions like this so I wouldn't have to waste two days and then have to ask anyway.
Thanks again.
Bion
|
|
|
|
|
You're welcome!
bions wrote: I wish the documentation was easier to plod through to find simple solutions like this so I wouldn't have to waste two days and then have to ask anyway.
We all do
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I need some quick help and i thought of the guru's on this forum. My cd/dvd rom won't read or write to Blank CD's. It reads Blank DVD's but says the file system is raw and has 0 bytes on the blank 4gb dvd.
I've tried to uninstall the cdrom and then searched for added hardware, but still nothing. what can i do?
|
|
|
|
|
You may want to try posting this on the Hardware board.
That's my quick help
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
But why did it take you three minutes to provide said help? Come on, Mark, that's not the philosophy around here.
"A good athlete is the result of a good and worthy opponent." - David Crow
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
|
|
|
|
|