Link to home
Start Free TrialLog in
Avatar of qqqqqqqqq
qqqqqqqqq

asked on

Using/Killing Threads?

I have a program that needs to constantly send output to a serial port device. The data it sends is updated every second. The calculation takes time. During the time when the calculation is being made, the serial port device is getting no input. This is shown in example 1:

while(1)
{
   // Make Calculation (takes .3 seconds)
   // Write to Serial Port (takes 1 second)
}

I figured that the natural way to fix this was using thread. So I changed my code to look like example 2:

threadfunction()
{
   // Write to Serial Port (takes 1 second)
}
while(1)
{
   // Make Calculation (takes .3 seconds)
   // Create New Thread (threadfunction)
}

This code however generates a big problem. The calculation which takes .3 seconds finishes quicker than the thread and the thread starts again before it has finished the first time. This causes the program to hang and Windows to crash when i quit the program. So I thought, hmmm, what if I used a Sleep(700) call to let the thread finish before it is started again. That however is a very bad move. In the future computers will get faster (i'm not developing on a state of the art machine either). The calculation will take less than .3 seconds. When that happens the thread will once again try to start itself over before it has finished the first time.

What i'm asking is how should i get around this problem. The only thing I could think of is illustrated in example 3:

threadfunction()
{
   // Write to Serial Port (takes 1 second)
}
while(1)
{
   // Make Calculation (takes .3 seconds)
   // Kill the Thread
   // Create New Thread (threadfunction)
}

I'm not sure if that would work. I know there might be like 1/100 of a second where there is no data being sent to the serial port but that is such a small time period that it probably won't be noticeable.


So the question here is: Does the killing of the thread make sense? If so how would i implement that on Win32/MFC? If not what works better?

Note: I tried putting the code in the thread function in a loop that would go until a bool variable was set to false, and i'd set that variable to false right where i put the "// Kill the Thread" line in example 3 however that waits for the thread to finish it current run through the loop. I would need instant termination.
Avatar of pellep
pellep
Flag of Sweden image

Well, one way to go about it is to create a stack with synchronized access (look into the class CCriticalSection on how to create synchronized sections in your code). Have your calculation threads push data onto the stack and have your serial output thread pop data out of the stack. As soon as data is available, the thread then outputs it to the serial port.
Avatar of qqqqqqqqq
qqqqqqqqq

ASKER

i looked at the class and i get an idea of what you mean however i have no clue how to implement it. However it does sound like the way to go. I would need constant data being transmitted to the serial port so i'd have to keep sending data until new data was avaliable. I'm offering 200 points for this question and willing to offer a few hundred more. I'd like help implementing this. Could you point me to a good article or code example that would help me out in this area?
If U r using the synchronous I/O then why u need these two threads ?
I think U can use the same thread for calculation and writing .


Or If u want two threads U can use synchronization objects.

Critical section ,Mutex  or events,


CRITICAL_SECTION m_syncSection;
InitializeCriticalSection(&m_syncSection);
while(1)
{
  EnterCriticalSection(&m_syncSection);
  // Make Calculation (takes .3 seconds)
  LeaveCriticalSection( &m_syncSection);

}



threadfunction()
{

  EnterCriticalSection(&m_syncSection);
  // Write to Serial Port (takes 1 second)
  LeaveCriticalSection( &m_syncSection);
}



I can't use the same thread because the serial device needs constant input. I need to constantly be sending it data. When i'm making calculations it's not writing to the serial port. I'm using a dedicated thread for the sole purpose of writing to the serial port. Could someone explain why i need this critical section stuff. I'm not worried about race conditions or anything, this data doesn't have to be perfectly real time either. I just need to make sure that data is always being written to my serial device.
if i'm reading your example correct the serial device would still have no input when the calculation is being made.
Do you understand what i'm trying to do?
The calculation and the writing to the serial port must run parallel to each other. That's why I chose multiple threads.
What u'r writing at the time of calc ?
here's an overview that might help you understand my program.

1.) the program inits and makes the first calculation
2.) the program launches a thread to write that data
3.) while the thread is writing data the program gets new data and makes the calculation again using this new data
4.) the thread finishes writing and is started again to write the new data

The problem with this is that the serial device is not continuously getting data. However if i don't wait for the thread to finish and try to start it my program freezes and my computer locks up.
steps 1 through 4 are a loop that goes on until the program is terminated
i need to change this so that the port is continuously getting data. Each transmission takes exactly 1 second. I need to make sure that every 1 second new data is transmitted. The calculation only takes .3 seconds so the data is ready in time. The only problem is that if i tried starting a new thread as soon as my calculation was done the computer crashes. I either need to start the thread at the beginning at just keep providing it with new data or i need to kill it right before i start a new one. Do you understand my problem? Do you need clarification?
> 1.) the program inits and makes the first calculation
> 2.) the program launches a thread to write that data
> 3.) while the thread is writing data the program gets
> new data and makes the calculation again using
> this new data
> 4.) the thread finishes writing and is started again to > write the new data

On step 3 u specified U will get new data at the time of writing.

where do u get new data?

The problem may be because of both threads accessing the same memory at same time. For avoiidng this U must need synch objects or U must use another method for avoiding this access violation.
Can U use the same thread ? Why ur killing the thread ?

Can U use the same thread ? Why ur killing the thread ?

here's how it works. the main program launches 2 thread. The first one goes into a loop. It calls a function to get the memory usage of the computer (a percentage), and store it in a variable (lets call it m_memory).
The program launches a second thread that reads that m_memory variable and multiplys it by 80 and sets it into another variable (lets call it m_eighty). This thread then uses a formula to come up with another number based on m_eighty (that part is the calculation). Then the thread starts another thread to write that value to the serial port. While the write is occuring it starts it's loop over again and calculates a new value for m_eighty based on what the current value for m_memory is. It then tries to create another thread to write this data to the serial port but the first thread hasn't finished yet and the computer crashes.

I hope that's enough detail. I'm trying my best to explain this. If you need more just ask. (now that i think about it i might need mutex, is that correct?)
i hope that my last post answers your question.
1. Ur first thread reading memory usage into m_Memory;

2. Ur calc thread reading this m_Memory variable.
   Here is one problem.( for accessing the same variable  in defferent thread U need one synchronization object.

U can use

First Thread

EnterCriticalSection(&m_ctMemory)
Read value to m_Memory
LeaveCriticalSection(&m_ctMemory)

Second Thread

EnterCriticalSection(&m_ctMemory)
Copy m_Memory to another variable
LeaveCriticalSection(&m_ctMemory)

EnterCriticalSection(&m_ctEighty)
Use new variable for calculations.
LeaveCriticalSection(&m_ctEighty)

Third Thread
EnterCriticalSection(&m_ctEighty)
Copy m_eighty to new local varibale
LeaveCriticalSection(&m_ctEighty)
Use new variable for calculations.

But there is one problem
I think U can't write data to same port at same time from deferent threads.So Use the same thread.

Which function Ur using to output

WRITE_PORT_ULONG() ????

















I'm using a MFC extension class i got off the internet. It lets me use a function called Write. I think that the details of writing to the serial port aren't relavent. You have a point when you say that I need to put all of my serial port code in 1 thread. I'm asking this. Which of these 2 models is better to use:

1.)
while(1)
{
// Make Calculation
// if(process is active) KillProcess(the one that uses the serial port)
// CreateProcess(the one that uses the serial port)
}

2.)
threadone()
{
 while(1)
 {
 // Make Calculation
 // Set result of calculation to m_newvalue variable
 }
}

threadtwo()
{
 while(1)
 {
 // Write(m_newvalue)
 }
}

I can't get this CreateProcess() ?????

U mean CreateThread?
oh sorry, yes thread.
note: in example 2 both thread are started when the program inits.
i meant KillThread and CreateThread and if(thread is active)
sorry!
qqqqqqqqq Sorry to say .

I think no need for Killing the thread .

If ur using the synchronization object. U can use the sam thread.Only need to create it on init (once).

If u want to keep the thread stopped upto the first calculation is over . Use one event or another method
with WaitForSingleObejct();



qqqqqqqqq Sorry to say .

I think no need for Killing the thread .

If ur using the synchronization object. U can use the sam thread.Only need to create it on init (once).

If u want to keep the thread stopped upto the first calculation is over . Use one event or another method
with WaitForSingleObejct();



I think I understand what you're saying, but I'm not sure. Could you show a little snippet showing how this would be accomplished? How would i be able to calculate the value without stopping the flow of data to the serial device?
qqqqqqqqq Sorry to say .

I think no need for Killing the thread .

If ur using the synchronization object. U can use the sam thread.Only need to create it on init (once).

If u want to keep the thread stopped upto the first calculation is over . Use one event or another method
with WaitForSingleObejct();



qqqqqqqqq Sorry to say .

I think no need for Killing the thread .

If ur using the synchronization object. U can use the sam thread.Only need to create it on init (once).

If u want to keep the thread stopped upto the first calculation is over . Use one event or another method
with WaitForSingleObejct();



Sorry for the duplication of comments
umm, you posted that 4 times.
that's ok
Where are U from ?
Could u please check the comments after 2 hours?
Sorry I have one team discussion.

i'm on the west cost of the USA. I'll be around in 2 hours. I assume from your message you will be posting then.
Thank you for your patience! This concept is a little new to me, but i'm willing to add several hundred points if we can get through this problem.
ASKER CERTIFIED SOLUTION
Avatar of job_s
job_s

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
U can change the MAX_BUFFER_SIZE to large value if Ur write program takes less time to complete the operation.
i'm reading your post right now
in the getdata function you use the variable m_dwArrayIndex, is this the Copy or Write Index? You also use the variable newdata. Should this hold the m_memory variable (in my example) or should it hold the m_eighty variable? One more thing. What about bStopThread. Where does that come into play?
Sorry  m_dwArrayIndex is the CWriteData::m_dwArrayCopyIndex,
newdata is the whole processed data. thatis data to write.

that's nothing if u want to stop thread before exiting process. U can change the value of this variable to true.
for Exiting from the while loop no need for that U can use
while(1) no problem.




Sorry  m_dwArrayIndex is the WriteData::m_dwArrayCopyIndex,

newdata is the whole processed data. that's data to write.


bStopThread is is a flag, if u want to stop thread before exiting process. U can change the value of this variable
to true for Exiting from the while loop, no need for that U can use while(1) no problem.

just curious. I stored the data to go in the place of newdata in a CString. The code won't accept that. How should i convert this to a data type that will work?
U want to write a CString to seriel port ?
which data type U want to write to port ?
U want to write a CString to seriel port ?
which data type U want to write to port ?

I assumed it as DWORD
my previous program wrote a CString to the serial port (or at least that's the type of parameter the write function i'm using takes, it probably changes it there)

Yes I do want to write a CString
Is that Write function supports CString?

if U want CString then U want ot change the following code
on my code to
>   DWORD          g_dwArray[MAX_BUFFERSIZE];


   CString         g_dwArray[MAX_BUFFERSIZE];

and one morething to do U must clear the CString after writing it to port.

UINT WriteData( LPVOID lParam )
{
    CString strTempText;
    while(!bStopThread)
    {
         EnterCriticalSection( &CWriteData::m_ctMemory );
         if( CWriteData::m_dwArrayWriteIndex > MAX_BUFFERSIZE )
              CWriteData::m_dwArrayWriteIndex = 0;
         strTempText = g_dwArray[CWriteData::m_dwArrayWriteIndex];
g_dwArray[CWriteData::m_dwArrayWriteIndex].Empty();
         LeaveCriticalSection( &CWriteData::m_ctMemory );
         
         //Write new data
         //Write(strTempText);



         ++CWriteData::m_dwArrayWriteIndex;
    }

}


Also, in the GetData function i'm calculating the baudrate to send data over the serial port (yes it changes dynamically because i'm working with really strange hardware). But to avoid innaccurate readings i have to use that calculation and set the baud rate in the WriteData function. This causes access errors. Do I need to do mutex type thing on this?

Note: i'm leaving for a week. I'm going to increase the points to 500 now and i'll be back next friday and finish up this question. Please answer the questions i've asked (see above) while i'm gone.

You have been a wonderful expert and have helped me learn a lot about how to do this. I've got it working 95%. Please hang in there while i'm gone. Thanks!
sorry to leave you hanging in the middle of this question.
Hi qqqqqqqqq,
     I'm from India, GMT+5:30
     Hope ur reply on friday.
regards
job_s

 
someeone said to use a stack.  Do not.  Use a queue instead.  One thread pushes data into the queue, the other thread pops data if it is available.  Use a synchronization object for the queue access.
Queue - Stack, same thing, but different. Stack is (usually) LIFO (last in, first out), Queue is (usually) FIFO (first in, first out). Choose according to your needs.
Avatar of ambience
a much easier way is to use a synchronized container for data, so say you increase your thread count to no matter how many , you dont need write much extra code.
job_s:
These two lines cause my program to crash (in the write thread). Do I need to use a critical section here?

strTempText = g_dwArray[m_dwArrayWriteIndex];
g_dwArray[m_dwArrayWriteIndex].Empty();

all experts: is what job_s is proposing the way to go? If not what are you suggesting is better?
OK, so if you don't have threads in your program, can you write a string to the serial port?  If so, then when you go to multiple threads, you need to have a QUEUE accessible by both threads. Then you will need a synch object to prevent concurrent access to the QUEUE.  A critical section will be the best choice here.  The two threads will work accordingly:  The producer thread will put strings into the queue.  The consumer thread will pop a string off the queue and send it out to the serial port.  Because you are using a queue, the data is popped by the consumer in the same order as the producer put it there.  

In job_s example, he is implementing a queue in terms of arrays, but it seems like he is just advancing the pointer and this will eventually run out of space.  
EnterCriticalSection( &CWriteData::m_ctMemory );
        if( CWriteData::m_dwArrayWriteIndex > MAX_BUFFERSIZE )
             CWriteData::m_dwArrayWriteIndex = 0;
        strTempText = g_dwArray[CWriteData::m_dwArrayWriteIndex];
g_dwArray[CWriteData::m_dwArrayWriteIndex].Empty();
        LeaveCriticalSection( &CWriteData::m_ctMemory );
       


Yaa surely u need critical section or any other synchronization object because the same array accessing from different threads. That will cause access violation.
Please note I'm from India +5.30 GMT

Regards
Job_s
I've been using that code the whole time. It was in your example. It still causes the same error.
what access vioation ?

will u please post that code or send it to me through mail
I'l try to help u.

my mailid is job_s@rediffmail.com

regards
jobs
I did not read every post above.  Sorry.  But here is how to do what you want:

1) Create an output thread.  It loops, checking a buffer.  When there is any data to send, it sends it )or some of it) and removes it from the buffer.  Otherwise, it does a Sleep(0) to give up its timeslice and then it waits for some new data to appear in its buffer.

2) Create a calculating thread.  I calculates new values for the Output thread to send.  When it has created a new value, it adds it to the end of the output buffer.

3) you are done
=--==-=-=-=-=-=-
It is really that simple.  The output thread is sending as fast as it can (it is sending whatever data has been prepared for it) and the calculating thread is calculating as fast as it can.

You probalby need to implement a simple semaphore so that the two threads are not accessing the buffer simultaneously.  You might want to use a circular buffer.  You might want to add a check to see if the calculating thread is getting too far ahead of the Output thread, and when that happens, discard some of the oldest part of the buffer.  All of these are really small implementation details.

-- Dan
ok heres my view again, make a synchronized container like say (its like a queue)


tamplate <class T>
class buffer
{
public:
  buffer()
  {
    // InitializeCriticalSection(&m_cs);
  }

public:
 
  void is_empty()
  {
     bool flag;
     Lock();
     flag = m_data.empty();
     UnLock();
     return flag;
  }


  void push_back( T &value )
  {
       Lock();
       m_data.push_back( value );
       UnLock(};
 }

  T pop_front()
  {
       T value;
       Lock();
       value = m_data.front();
       m_data.pop_front();
       UnLock();
       return value;
  }

private:
  void Lock() { EnterCriticalSection(&m_cs);
  void UnLock() { LeaveCriticalSection(&m_cs);

private:
   CRITICAL_SECTION m_cs;
   std::list< T > m_data;
};

given that you can create your global buffer of any type like

buffer < DWORD > g_buffer;

UINT calc_thread(LPVOID)
{
    while(!quit_flag)
    {
         vl = calculate_value();
         g_buffer.push_back( vl );
    }
}

UINT send_thread(LPVOID)
{
    while(!quit_flag)
    {
        if(! g_buffer.is_empty())
        {
             vl = g_buffer.pop_front();
             send_to_device( vl );
        }  
    }
}

and more or less all what need to be there.
oh and BTW you can use a CList instead of std::list if you want to be loyal to MFC.
thank you to all the experts that participates in this question. I ended up finding that the most practical way to accomplish my goal was to use a method that I derived from job_s's method. Your help was greatly appreciated.
Thanks