-
Odd declaration
Hello everyone, I've been running into some problems writing code for my boss and I was wondering if you could help me. You see, I have a function that is called after clicking a button on a GUI. Inside this function I make the declaration:
Code:
SuspendCount=PortThread[PortNumber-1]->ResumeThread();
Where PortThread is a CWinThread* and SuspendCount and the return on ResumeThread() are DWORDs. The odd occurance arises when debugging the same declaration in a previous version of the code that I am trying to re-create. When doing so, stepping into (or over, for that matter) that line of code, it initiates this line of code:
Code:
DWORD aword = ::WaitForMultipleObjects(2,EventHandles,FALSE,INFINITE);
And only that declaration in a completely different source file and unrelated function. Can anyone explain why this may happen? (I'll put more code up if this isn't enough information.)
-
Perhaps you're debugging an old version of the program? If the source file is more recent than the executable, it will often tell you the wrong line numbers.
Also, if you have optimisation enabled, it will do strange things, jumping around between random-seeming lines.
Of course, you're probably familiar with both of these points, but I can't think of anything else at the moment. Perhaps you might want to post a bit more code, or better yet a debugger session (if you're using a command-line debugger).
-
Yeah, I tried rebuilding and different optimizations and neither worked.
Code:
PortThread[3]= AfxBeginThread(StartCryptoPortThread, &Port[3],THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
UINT C_Control::StartCryptoPortThread( LPVOID pParam )
{
char* buffer;
int size = 0;
C_RS_422_Port* pObject = ( C_RS_422_Port*)pParam;
if (pObject == NULL )
return 1; // if pObject is not valid
else
{
//C_Control::GetOutboundMessage(buffer,size);
pObject->Send_Crypto_Key_1(); // do something with 'pObject'
return 0; // thread completed successfully
}
}
void Crypto_Dlg::OnBnClickedCryptoPortAct()
{
CString sString;
CButton* pButton;
const bool Active = TRUE;
pButton = (CButton*)GetDlgItem(IDC_Crypto_Port_Act);
pButton->GetState();
if (pButton->GetCheck())
{
pButton->SetCheck(0);
pButton->SetState(0);
GetDlgItemText(IDC_Crypto_Port_Act,sString);
if (!sString.Compare("Activate"))
{
Executive.Set_Activate(3, Active);
SetDlgItemText(IDC_Crypto_Port_Act,"Deactivate");
}
else
{
Executive.Set_Activate(3,!Active);
SetDlgItemText(IDC_Crypto_Port_Act,"Activate");
}
m_b_Crypto_Port_Act = TRUE;
}
if (m_b_Crypto_Port_Act)
{
Executive.On_Crypto_Apply_Event();
m_b_Crypto_Port_Act = FALSE;
}
if(!Executive.b_Port_Open[3] && ((CButton* )GetDlgItem(IDC_Crypto_Port_Act))->GetCheck() )
{
Executive.OpenPort(3, m_Port_Number);
}
// UpdateData(TRUE);
// UpdateWindow();
}
void C_Control::On_Crypto_Apply_Event()
{
// this function controls the thread starting and stopping.
// the threads are synchronized on a start and a stop event.
// the thread functions that this functions controls are
// those that write data to the ports and to the log files
// if port is currently inactive - start and set timing
if (!b_Port_Status[3])
{
goto startports;
}
else // port already active
{
Activate_Crypto_Port(4, FALSE);
goto startports;
}
startports:
Activate_Crypto_Port(4, TRUE);
Port[3].StartTransmission.SetEvent();
}
bool C_Control::Activate_Crypto_Port(int PortNumber, bool ActiveYN)
{
// this function starts or suspends a port thread depending
// on the state of ActiveYN and opens the log files the first
// time a port is activated
static int Times_Through[4] = {0,0,0,0};
DWORD SuspendCount;
if (ActiveYN) //activate
{
if (Times_Through[PortNumber-1]==0)
{
// Open the log files only the first time a write event happens
// Port[PortNumber-1].OpenLogFiles(FileNames[PortNumber-1]);
Times_Through[PortNumber-1]=1;
}
SuspendCount=PortThread[PortNumber-1]->ResumeThread();
//code based on SuspendCount
}
UINT C_RS_422_Port::Send_Crypto_Key_1()
{
DWORD aword = ::WaitForMultipleObjects(2,EventHandles,FALSE,INFINITE);
//more code
}
There's all the relevant code without going too overboard. Also, the first time SuspendCount is declared in this section, it will be assigned a valid number.
-
> PortThread[3]= AfxBeginThread(StartCryptoPortThread, &Port[3],THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
> C_RS_422_Port* pObject = ( C_RS_422_Port*)pParam;
Put a breakpoint in the thread function, and compare the red bits.
If they're different, then the object you thought you were pointing at, is not what you expected.
You have to remember that all class member functions get passed a hidden 'this' pointer.
You also have to remember that the thread library doesn't know this.
Class member functions which get passed (as a pointer to a function) to say a thread library need to be declared static to suppress the 'this' pointer.
-
Do you have a global StartCryptoPortThread function?
If not, this should not compile.
-
It won't let me get to pObject in the debugger. I don't think thats the problem though, the pre-existing code that I'm trying to replicate and expand upon seems to handle that part just fine.
-
Then perhaps you should compile it as Debug instead of Release? That is a typical problem when you use Release.
-
I'm not quite sure what the difference is between the two, the problem is I can't step into the StartCryptoPortThread function from the declaration and when i put a breakpoint in the function itself, it never gets there.
-
Debug -> build used for debugging.
Release -> build shipped to customers (finished build).
For one thing, debug builds disable optimizations.
-
Okay, that's what I figured, but how do I distinguish between the two when compiling? All I've been doing is hitting F5 or the Play button next to "Debug."
-
Oh, now I see the drop down box, yeah, I was using Debug, not Release.
-
PortThread[3]= AfxBeginThread(StartCryptoPortThread, &Port[3],THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
You should make sure this is being called from a function somewhere, and you are 100% sure that it is being called before resuming the thread, and that the call is succeeding. This seems like the most likely culprit, since it most closely resembles what might be expected from "undefined behaviour" as pertaining to OS thread scheduling. Without more clues to go by though, it's hard to say.
SuspendCount=PortThread[PortNumber-1]->ResumeThread();
I assume you have verified that PortNumber is indeed 4 at this line of code, and that PortThread[3] is a valid value?
-
PortThread[3]= AfxBeginThread(StartCryptoPortThread, &Port[3],THREAD_PRIORITY_NORMAL,0,CREATE_SUSPENDED);
That is being defined in the constructor of the Port[] instances. And yes, PortNumber is indeed 4.
-
*shrug*
>and that PortThread[3] is a valid value?
Not meaning to be nitpicky, but have you put a breakpoint in the constructor to ensure that the thread creation is not failing? Also, you'll want to ensure that the value of PortThread[3] doesn't change between the constructor and Activate_Crypto_Thread(). Could be some random piece of code in this 'old version' is reassigning that without you realizing it.
One other thing, along the same lines - You'll want to doublecheck that the handles in EventHandles are being properly initialized, and remain initialized at the time when Send_Crypto_Key_1() is being called.
I still think it sounds like something's uninitialized, or become de-initialized, before calling an OS scheduling function somewhere.
-
What is the scope of Port?
Does it last at least as long as all the threads?
Have you taken into account (see earlier posts) that the thread API cannot return a proper 'this' pointer to a C++ class member function?
Post your latest code.