|
Hi,
I like to draw lines with delay but using threads. The data will be fetched from different list (m_lstpoints). they have to be drawn simultaneously. When i tried to do this i am getting illegal.
I am very much new to threads. Can u help me.
//Code
CRITICAL_SECTION g_csGDILock; //Initialized
AfxBeginThread(DrawStrokesUsingThrd, (LPVOID)pTInfo1);
AfxBeginThread(DrawStrokesUsingThrd, (LPVOID)pTInfo2);
AfxBeginThread(DrawStrokesUsingThrd, (LPVOID)pTInfo3);//This list
is dynamic
//The pTInfo contains the g_csGDILock pointer and other info
//to draw points such as dc and list of points.
void CPlotPoints::TDrawPoints(HDC hdc, PRTL_CRITICAL_SECTION pMutex){//Non static
POSITION pos =NULL;
CPoint pt1, pt2;
pos =m_lstPoints.GetHeadPosition();
pt1=(CPoint) m_lstPoints.GetNext(pos);
while (pos){
EnterCriticalSection(pMutex);
{
pt2=(CPoint) m_lstPoints.GetNext(pos);
CDC dc; //hdc is a CClientDC
dc.Attach(hdc);//I had even tried to Send CClientDC* directly
//Plot code begins
//Here we draw rectangles,lines or something using dc
//dc.Moveto(pt1); //These lines are giving assertion
//Plot code ends here
dc.Detach();
GdiFlush();
}
LeaveCriticalSection(pMutex);
Sleep(300);
}
}
Thank you.
Manu
|
|
|
|
|
|
Several remarks first:
- You don't describe which problem you are having: "i am getting illegal" is not very informative sentence to me
- Use the pre tags to format your code properly because it is almost unreadable.
- Please, read the posting guidelines on top of this forum.
Now for your problem: if you are trying to draw things from multiple threads, that's probably why your code crashes. You should only have the main thread that access the UI.
|
|
|
|
|
Sir,
You got it. I am sorry to say this that i mentioned in the code
with a comment where i am getting illegal or assertion dailog.
("//dc.Moveto(pt1); //These lines are giving assertion").
I am clearly and purposefully making my child threads to
draw the lines. What is the alternative. More over i had initialized
the critical section also.
1. Shall i ask the view to redraw the points by sending the points
2. or else i have to do something else.
Thanks for answering my question.
Regards,
Manu
|
|
|
|
|
kanduripavan wrote: 1. Shall i ask the view to redraw the points by sending the points
Yes, you should find a mechanism that let the view (and only the view) redraw the data? Everything that is 'generated' from the threads should be independant from the view. You'll need to store this data somewhere and inform the view that new data is available by sending a message to the view. Access to the data should also be protected with critical sections (for example).
|
|
|
|
|
Sir,
Thank you very much. I am very much new to threading.
I like to plot points without timer and using threads only.
The output which i wanted was that each points has to be plotted
individually. Nothing professional. i am just entering into this
new world of threading and experiencing the problems of multi thread
programming if i am going to implement in near future.
I will try and implement the same and get back to you.
I saw similar kind of codes in MTGDI but they are subclassed(CWinthread).
I want to experiment if a particular section of the code is implemented
by multiple threads then what will happen.What will happen to CList object poistion variables, and impact of other things. This is my intention.
Thank you very much.
Manu
|
|
|
|
|
Hi,
I did it as you said. It has fixed my problem of plotting multiple points simultaneously.
<br />
EnterCriticalSection(pMutex);<br />
{<br />
<br />
pt2=(CPoint) m_lstPoints.GetNext(pos);<br />
pView->SendMessage(ID_VIEW_DRAWOFFLINE, (LPARAM)&pt1,(WPARAM)&pt2 );<br />
LeaveCriticalSection(pMutex);<br />
}<br />
<br />
Thank you very much Cédric Moonen, Mark Salsbery,Suman and others who looked after my issue.
|
|
|
|
|
And, It seems to me you are using document view architecture. I understand MFC framework has mechanism for achieving this type of requirement.
Have a look at CDocument::UpdateAllViews() and
CView::OnUpdate
"Typically you should not perform any drawing directly from OnUpdate. Instead, determine the rectangle describing, in device coordinates, the area that requires updating; pass this rectangle to CWnd::InvalidateRect. This causes painting to occur the next time a WM_PAINT message is received." from msdn.
This allows all the drawing code happens in WM_PAINT message than custom message.
In your thread modify the members of document object which stores the points and call UpdateAllViews(). which finally results WM_PAINT message for the views, in the paint handler of the view get the points from Document object (must be synchronised) and draw the view.
|
|
|
|
|
You can do drawing from another thread, but you need to really understand thread
synchronization.
Nothing in GDI is thread safe, so ALL GDI operations need to be synchronized between threads.
Have you initialized your GDI critical section?
Do you have one and ONLY one critical section object shared by all the threads?
If you answered no to either of those, you aren't using thread synchronization objects correctly.
Don't forget to synchronize the UI thread as well.
What is causing the assertion? You should be able to look right at the offending line of
code in the debugger.
What is the exact assertion message?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I have one one critical section shared by all the threads. I had Initialized the critical section before creating the child threads.
I have 2 doubts.
1.The critical section is initialized by the UI Thread ie by the primary thread. So is it there it can go wrong.
2.Lets leave the GDI issue and consider the handle as a shared object
which is inside the critcal section. SO how can the 2nd or the 3rd thread can enter and access it. As a beginner it seems for me that is is not logically valid. (the thread trying to acess gdi handles which is inside the critical section). I am extremely sorry to say these lines.
The assertion is shown in GDI files. But as far as i know it occured
due to the line
dc.LineTo(pt1);//From here onwards the error might have occured
I like to thank you for supporting the one who doesnt knows anything.
Thank you.
|
|
|
|
|
kanduripavan wrote: 1.The critical section is initialized by the UI Thread ie by the primary thread. So is it there it can go wrong.
Any thread can initialize it, as long as it's initialized before a thread tries to use it.
kanduripavan wrote: consider the handle as a shared object
which is inside the critcal section
This is only a logical way to think about it. In reality, there's no protection of the handle by the critical section.
What the critical section does is prevent execution of code by a thread until another thread owning the critical section
releases the critical section. This can be used to prevent two threads from using/changing the same handle/variable/data or
any other resource shared by multiple threads. Critical sections can also be used just to prevent two threads from
executing the same code simultaneously - there doesn't have to be any data or other resource involved.
kanduripavan wrote: The assertion is shown in GDI files
You have the source code - what's the line of code??
Using MFC may not work for what you're doing, since MFC has internal containers that are thread-specific.
To get around this, you can use an HDC directly instead of through the CDC and derived classes.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I looked at the MFC source code - the only way I can see LineTo() asserting is if
the HDC is NULL.
That's a problem elswhere in the creation of your dc.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
hi ,
Thats great as what you said. The problem was in creating the dc.
The code was
<pre>
void CThreadDemoView::OnMenuOffline()
{
// TODO: Add your command handler code here
CClientDC dc(this);
CreateThreadsToPlot(pDC, CPoint(100,100) );
}
</pre>
CreateThreadsToPlot will create the required no of threads to plot the
points.
After seeing your reply i tried this as a last attempt before giving it up. I went and browsed into the gdi code and found that my dc was not null. but surprisingly i think its invalid. This could be probably one
of the reason i might have got the assertion. The code change was
<pre>
void CThreadDemoView::OnMenuOffline()
{
// TODO: Add your command handler code here
CDC* pDC =GetDC();<B>//code changed here only</B>
CreateThreadsToPlot((CDC*)pDC, CPoint(100,100) );
}
</pre>
This way of getting the DC has fixed the same issue without changing
not even a single line of code in the program.
Thank you very much Mr. Mark Salsbery.
By,
Manu
|
|
|
|
|
How can I get the mouse position when i click Right Button on the CListCtrl?
|
|
|
|
|
On the mouse click message mapping function use following code
DWORD pos = GetMessagePos(); <br />
CPoint pt(LOWORD(pos), HIWORD(pos));
|
|
|
|
|
which message you are using,
NM_RCLICK notification gives the LPNMITEMACTIVATE structure which contains ptAction member gives the position.
|
|
|
|
|
Hello. I'm trying to set up a window that automatically does some financial calculations and I'm using spin controls with a buddy window. Everything is working fine except for one small problem. I would like to fire an event after the quantity in the spin control's buddy window changes. However, my event options (UDN_DELTAPOS, NM_RELEASEDCAPTURE, etc.) don't seem to allow for this. Does anyone out there know how to fire an event after the spin button has been clicked? This is driving me bonkers. Thank you.
|
|
|
|
|
From the docs:
"An up-down control notifies its parent window when its current position
changes by sending it a UDN_DELTAPOS notification message and a
WM_VSCROLL or WM_HSCROLL message."
None of these messages are what you need?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Perhaps the Scrolling messages are what I need. The DELTAPOS message gets fired before any changes are made so that doesn't really help me. I'll give the vertical scroll message a shot. Thanks a lot.
|
|
|
|
|
If the buddy window is a single line edit control, maybe the EN_CHANGE notification
from the edit control?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
The EN_CHANGE is what did it. For some reason I couldn't intercept the scroll messages. Problem solved and thanks again. I'd be lost without the Code Project.
|
|
|
|
|
Cool good to know that works (I didn't test it).
Cheers,
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
How can I:
- assign a variable to a Radio Button control
- set the initial state to such an object
In VC++6, please
36. When you surround an army, leave an outlet free.
...
Do not press a desperate foe too hard.
SUN-TZU - Art of War
|
|
|
|
|
http://www.codeproject.com/KB/tips/HowToUseGoogle.aspx[^]
In this case, I'd make sure I include the term 'MFC' in my google search.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|