How to prevent cpu-bound thread locking out UI thread

  • Thread starter Thread starter David J. Marcus
  • Start date Start date
D

David J. Marcus

Hi

I have an application that has a UI thread and a file-content-searcher
thread which asynchronously searches a large (1GB+)file for occurrences of a
user-specified string.

I start the file-searching thread with a ThreadPriority.Lowest to make sure
it does not monopolize the cpu cycles.

However, what I see is that screen repaints stop until the file-searcher
thread completes (or I put in artificial Sleep calls).

I've tried inserting judicious 'Sleep(0)' in the file-searcher thread but to
no avail.

What am I missing?

Is there a way to have Windows (XP) dispatch events to the UI thread even
though there is a separate thread in my process that is running?

-Any help would be greatly appreciated
David
 
Hi David,

David J. Marcus said:
Hi

I have an application that has a UI thread and a file-content-searcher
thread which asynchronously searches a large (1GB+)file for occurrences of a
user-specified string.

I start the file-searching thread with a ThreadPriority.Lowest to make sure
it does not monopolize the cpu cycles.

However, what I see is that screen repaints stop until the file-searcher
thread completes (or I put in artificial Sleep calls).

You are probably doing something wrong.
I've tried inserting judicious 'Sleep(0)' in the file-searcher thread but to
no avail.

What am I missing?

Can you show us the code related to thread starting?
 
Hello David,

Thanks for your post. I reviewed your description carefully, and now I'd
like to share the following information with you:

Does the problem still occur if you put Sleep(500) in the worker thread? If
so, I am afraid that you may use some synchronization objects say, mutext,
etc, which may synchronize the UI and worker threads.

In addition, I agree with Miha that you can provide a simple reproducible
sample/code snippet which will be most helpful for us to pinpoint the
problem and resolution.

I look forward to hearing from you.

Regards,

HuangTM
Microsoft Online Partner Support
MCSE/MCSD

Get Secure! -- www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Tian Min Huang said:
Hello David,

Thanks for your post. I reviewed your description carefully, and now I'd
like to share the following information with you:

Does the problem still occur if you put Sleep(500) in the worker thread? If
so, I am afraid that you may use some synchronization objects say, mutext,
etc, which may synchronize the UI and worker threads.

I've tried 'Sleep' with different parameters, including, as you can see
below, '0'. The documentation explicitly states that Sleep(0) yields control
to other threads. I suspect that what is happening is that the worker thread
is indeed being given lowest priority but since it is always 'ready-to-run'
the Windows dispatcher appears not to dispatch UI repaint events (as long as
there is a thread in the process ready to run).

The file being searched is very large, often in the GB range. The worker
thread is scanning 1MB chunks. While it is possible to add 'Sleep(500)' once
in the beginning, it is not viable on every iteration. In a 1GB file, there
will be 1000 iterations.

The symptoms: once the worker thread starts, screen updates stop. When the
thread finishes, the screen repaints. In normal operation the user kicks
off a search of the file and continues to work with the rest of the UI.
While the search is going, the UI uses a timer to refer to the status of the
search and updates status field on the screen. What I see is only the final
status (the thread is done) then the screen comes back.

My objectives: to have the worker thread not interfere with the UI event
dispatch mechanism (repaint in particular). I was hoping that by setting the
worker thread's priority to the lowest it would soak up 'unused' cycles
only.

Lastly, I can't imagine how a mutex would help in this situation. The last
resort is switching from a search thread to a different process which is
much more awkward.
In addition, I agree with Miha that you can provide a simple reproducible
sample/code snippet which will be most helpful for us to pinpoint the
problem and resolution.

The thread starting code:

public void StartSearch()
{
Thread thread = new Thread(new ThreadStart(runSearch));
thread.Name = "logFileSearcher";

//-- make sure thread does not constipate normal threads
thread.Priority = ThreadPriority.Lowest;

//-- kick off the thread
thread.Start();
}


The worker thread (asynchronous portion)

private void runSearch()
{
//-- open our copy of file handle to file
//-- try to open the file (shared with creator)
fs = File.Open(fileName, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite);

//-- position to start of search spot
currentOffset = fs.Seek(startOffset, SeekOrigin.Begin);

//-- 1MB read into memory
loadChunk();

//-- leading byte
byte leadByte = (byte)searchString[0];

//-- yield to other threads including UI
Thread.Sleep(0);

while (!abortSearch)
{
try
{
while (true)
{
advance:
if (buffer[buffOffset++] != leadByte)
continue;

//-- compare the rest of the string
int j = 0;
for (int i = 1; i < searchString.Length; j++, i++)
{
if (buffer[buffOffset + j] == (byte)searchString)
continue;

//-- we have a mis-match
goto advance;
}

//-- we have a match
lock (this)
{
matchesFound.Add(startOffset + buffOffset);

//-- yield to other threads
Thread.Sleep(0);
}

//-- skip over matched string
buffOffset += searchString.Length;
}
}
catch
{
//-- ran off end of buffer... load next 1MB chunkr
currentOffset += buffOffset;
loadChunk();

//-- check for end of file
if (buffer.Length == 0)
break;

//-- yield to other threads
Thread.Sleep(0);
}
}

if (abortSearch)
searchStatus = eStatus.Aborted;
else
searchStatus = eStatus.Done;
}
}
I look forward to hearing from you.

Thanks for your prompt help

-David
 
David J. Marcus said:
I have an application that has a UI thread and a file-content-searcher
thread which asynchronously searches a large (1GB+)file for occurrences of a
user-specified string.

I start the file-searching thread with a ThreadPriority.Lowest to make sure
it does not monopolize the cpu cycles.

However, what I see is that screen repaints stop until the file-searcher
thread completes (or I put in artificial Sleep calls).

I've tried inserting judicious 'Sleep(0)' in the file-searcher thread but to
no avail.

What am I missing?

Is there a way to have Windows (XP) dispatch events to the UI thread even
though there is a separate thread in my process that is running?

It should do so already. How sure are you that you've got the
asynchronous bit right? Could you post a short but complete example?

See http://www.pobox.com/~skeet/csharp/complete.html for what I mean by
that.
 
Hi Jon,

He has already posted it in an answer to Tian.
I can't see anything wrong, can you?
 
He has already posted it in an answer to Tian.

No he hasn't - he's posted code, but it's not complete. In other words,
I can't just cut and paste it, compile and then run it.
I can't see anything wrong, can you?

Not immediately, no. That's the beauty of posting *complete* code - I
could have reproduced it by now and quite possibly found what was wrong
if the code had followed the guidelines I specify in
http://www.pobox.com/~skeet/csharp/complete.html
 
Hello David,

Thanks for your response. I'd like to share the following information with
you:

1. The reason I mention a mutex is to make sure that you do not use any
synchornization objects what synchronize the execution of the UI and worker
threads. For example, if one thread use mutex to lock shared resource,
other thread which will also need to access the resource have to wait until
the previous one unlock the mutex. That will cause the same problem you are
experience.

2. I reviewed your code snippet, however, I did not find any obvious
problem. Since the code is incomplet, I do not know how loadChunk() is
implemented, and if the UI thread will also open and access the search
File. Is it possible for you to provide a simple reproducible sample?

I am standing by for your response.

Regards,

HuangTM
Microsoft Online Partner Support
MCSE/MCSD

Get Secure! -- www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Hi

First and foremost, my thanks to the group for their eagerness to help.

The entire application is too large to post. The test data alone is almost
1GB in size.

I will do some more research (will put trace statements with time stamps)
and analyze the sequence more completely. From that I hope to be able to
synthesize a small test program that demonstrates the problem. I'll report
back with the results. I am still hoping the problem is in my code.

-TIA
David
 
Back
Top