Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 802
  • Last Modified:

Thread started with AfxBeginThread() hogging CPU

I have CDialog based modal dialog that invokes a fairly lengthy processing step using the following call:

Thr=AfxBeginThread(MyFunction, pPam, THREAD_PRIORITY_LOWEST);

The thread starts up and runs nicely to completion.   However I have a CProgressCtrl on the invoking modal dialog that I want to update while the lengthy process is happening.

I have a timer set in the dialog that calls me every 100 ms.  At that time I attempt to set the progress bar using SetPos().  The problem I have is that I have to call Sleep() in the spawned thread in order to give the dialog a chance to update the progress bar.

I would have thought that the dialog would have gotten some cycles especially when I used  THREAD_PRIORITY_LOWEST for the spawned thread.

Is the main thread expected to get no cycles unless the spawned thread does some sleeping?

I'm running on a reasonable machine (Intel i5).
0
allanephillips
Asked:
allanephillips
  • 4
  • 3
1 Solution
 
Tony GiangrecoCommented:
Have you tried limiting the time alloted to the sleep command?
0
 
allanephillipsAuthor Commented:
Yes I have.  It seems as though I have to give it about 100 ms before things work.  That seems like a lot of time.
0
 
OrcbighterCommented:
Can you show some of the code in the MyFunction process?
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

 
allanephillipsAuthor Commented:
Here is the complete source.  It simply does symtax highlighting of some XML.  Of course it's fairly CPU intensive.


UINT __cdecl MyFunction(LPVOID pParam)
{
	Thread_t *pThread = (Thread_t *)pParam;

	pThread->lPos = 0;
	bool bReturn = MySyntaxHighlightFile(pThread->sInputName, pThread->sOutputName, &pThread->lPos);

	return 1;
}


// Copy the input file to the output file inserting RTF markup to syntax color the XML.
bool MySyntaxHighlightFile(const wchar_t *sInputFileName, const wchar_t *sOutputFileName, long *lPos)
{
	FILE *fpIn;
	_wfopen_s(&fpIn, sInputFileName, L"rb");
	if (!fpIn)
		return false;

	FILE *fpOut;
	_wfopen_s(&fpOut, sOutputFileName, L"wb");
	if (!fpIn)
		return false;
	char sTag[1000];
	iTagIndex = 0;
	sTag[0] = 0;

	long long i64FileLength = _filelengthi64(_fileno(fpIn));
	long long i64Step = (long long) ((i64FileLength / 60.0) + 0.5);
	long long i64CurPos = 0;

	bool bInTag = false;
	bool bInAttributes = false;
	bool bAttrValue = false;

	char sBOM[3];
	fread(sBOM, 1, 3, fpIn);				// Swallow the byte-order-mark.

	fputs("{\\rtf1{{\\colortbl ;"
			"\\red0\\greeen0\\blue0;"				// Regular text - black	= 1
			"\\red255\\green0\\blue0;"				// ObjectTag color		= 2
			"\\red0\\green128\\blue255;"			// Tag color			= 3
			"\\red0\\green0\\blue255;"				// Quote color			= 4
			"\\red30\\green150\\blue30;"			// Attribute name color	= 5
			"\\red0\\green0\\blue255;"				// Angle color			= 6
			"\\red192\\green192\\blue192;"			// Comment color		= 7
			"\\red0\\green128\\blue255;}"			// PI color				= 8
			, fpOut);

	unsigned iChar;
	while ((iChar = fgetc(fpIn)) != EOF)
	{
		i64CurPos++;
		switch (iChar)
		{
		case '\r':
			break;						// Don't need carriage returns.

		case '\n':
			fwrite("\\par ", 1, 5, fpOut);
			break;

		case '{':
		case '}':
		case '\\':
			fputc('\\', fpOut); 
			fputc(iChar, fpOut);
			break;

		case '<':
			{
				fputs("\\cf6 ", fpOut);
				fputc(iChar, fpOut);
				int iNextChar = fgetc(fpIn);
				i64CurPos++;
				switch (iNextChar)
				{
				case '!':
					fputs("\\cf7 ", fpOut);
					fputc(iNextChar, fpOut);
					break;

				case '?':
					fputs("\\cf8 ", fpOut);
					fputc(iNextChar, fpOut);
					break;

				case '/':
					fputc(iNextChar, fpOut);
					bInTag = true;
					iTagIndex = 0;
					break;

				default:
					bInTag = true;
					iTagIndex = 0;
					sTag[iTagIndex++] = iNextChar;
					sTag[iTagIndex] = 0;
				}
			}
			continue;

		case '>':
			if (bInTag)
			{
				OutputTag(sTag, fpOut);
				bInTag = false;
			}
			bInAttributes = false;
			fputs("\\cf6 ", fpOut);
			fputc(iChar, fpOut);
			fputs("\\cf1 ", fpOut);
			break;

		case ' ':
			if (bInTag)
			{
				OutputTag(sTag, fpOut);
				bInTag = false;
				bInAttributes = true;
			}
			fputc(iChar, fpOut);
			break;

		case '"':
			if (bInAttributes)
			{
				if (bAttrValue)
					fputs("\\cf4 \"\\cf5 ", fpOut);		// Closing quote for attribute value.
				else
					fputs("\\cf4 \"\\cf1 ", fpOut);		// Opening quote for attribute value.
				bAttrValue = !bAttrValue;
			}
			break;

		default:
			if (bInTag)
			{
				sTag[iTagIndex++] = iChar;
				sTag[iTagIndex] = 0;
			}
			else if (iChar <= 0x7F)
				fputc(iChar, fpOut);
			else
			{
				// Now we have to convert this UTF8 extended character to Unicode.
				unsigned char sUtf8[11];
				int iIndex = 0;
				sUtf8[iIndex++] = iChar;

				// Read in all the bytes of this unicode character.
				while ((iChar = fgetc(fpIn)) != EOF)
				{
					if ((iChar < 0x80) || (iChar > 0xBF) || (iIndex > 9))
						break;
					sUtf8[iIndex++] = iChar;
					i64CurPos++;
				}
				i64CurPos--;
				ungetc(iChar, fpIn);

				sUtf8[iIndex] = 0;
				wchar_t *sUnicode = ATW::UTF82Wide((char *)sUtf8);

				fprintf(fpOut, "\\u%d ?", *sUnicode);	// Extended character.
			}
		}
		if ((i64CurPos % i64Step) == 0)
			(*lPos)++;
	}

	fputs("}", fpOut);

	fclose(fpIn);
	fclose(fpOut);

	return true;
}

Open in new window

0
 
OrcbighterCommented:
Sorry, I meant the section of code where you call sleep, and the section of code where you pass information to update the progress bar.
0
 
allanephillipsAuthor Commented:
The code that updates the progress bar is simply:

    mProgressBar.StepIt();
    mProgressBar.UpdateWindow();

Open in new window


inside OnTimer().

The Sleep() call was at this point in the code I sent:

     if ((i64CurPos % i64Step) == 0)
      {
	  (*lPos)++;
          Sleep(100);
       }

Open in new window


This does actually work but 100 ms seems like a lot of time effectively doing nothing.
0
 
OrcbighterCommented:
Okay, from what I can see and imply from the code you haven't supplied is this:
1. You start a thread to do some stuff which is compute-intensive, and seems to swallow up your CPU. Your timer events might be being queued as a result.
2. You have a timer that periodically calls progress.StepIt() to advance the visual display bar.
3. You found that you had to add a Sleep command to the compute-bound thread in order for the display update to get enough time to update the display, and that you had to increase the amount of time in the Sleep for it to work.

On point 1: Yes, without some kind of break in the thread process, it would consume CPU resources.
On point 3: My thoughts are that, if the timer event does not helpfully coincide with the Sleep command, it would not get enough time to act, thus you had to keep increasing the Sleep time in the thread, ie, the Sleep window in the background thread does not coincide with the window of the timer event.

Suggestions:
1. Change the Sleep command in the thread function back to 10 ms (the smallest effective amount of time you can get).
Now that the Sleep is so small, you can afford to sleep more times (more than i64CurPos % i64Step times). Thus your sleep will relinquish control for far shorter periods of time, but the increased frequency of the Sleep calls means other threads might get a look in.

2. If point 1 fixes the problem, good. If not, maybe consider another option rather than a timer.Instead of the timer, use a Windows Event and send that to an event handler in the dialog that updates the progress bar.
An additional thought is that the timer event that updates the Progress bar has no real link with the position of the file being processed. The time fires and just arbitrarily increments the progress bar. An event message might allow you a more connected link with the stepIt command by adding a parameter to the event message (but that might be version 2, yes ? :-) )
0
 
allanephillipsAuthor Commented:
I'm accepting this even though I have not been able to make use of the information.  It feels as though threads are still useless on Windows so I've just dropped the separate thread.

When one spins off a thread with the priority set to "THREAD_PRIORITY_LOWEST" and the other thread(s) get no cycles without doing a call to Sleep() then it's obvious that threads have not been implemented in Windows in a way that's useful yet.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now