5

There is (or there has been) a lot of talk about wether it's good or bad to use the Thread.Sleep() method. From what I understand it is mainly to be used for debugging purposes.

Now I wonder: is it bad to use for my specific purpose, that is, constantly looping it to be able to pause/resume the thread? I do this because I want to pause a thread that performs I/O operations and be able to resume it in a simple way.

The I/O operations are basically just writing blocks of 4096 bytes to a file until all the data has been written to it. Since the file might be large and take a long time I want to be able to pause the operation (in case it would start eating much system resources).

My code, VB.NET version:

'Class level.
Private BytesWritten As Long = 0
Private Pause As Boolean = False

'Method (thread) level.
While BytesWritten < [target file size]
    ...write 4096 byte buffer to file...

    While Pause = True
        Thread.Sleep(250)
    End While

    ...do some more stuff...
End While

C# equivalent:

//Class level.
long bytesWritten = 0;
bool pause = false;

//Method (thread) level.
while(bytesWritten < [target file size]) {
    ...write 4096 byte buffer to file...

    while(pause == true) {
        Thread.Sleep(250);
    }

    ...do some more stuff...
}

I have heard about ResetEvents and I know a little bit about what they do, but I have never really looked much into them.

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • 2
    I would use a manual reset event. After each chunk, wait on the event. To pause the thread, reset the event. To resume the thread, set the event. – Raymond Chen Jul 23 '16 at 20:45
  • 2
    I don't understand why you would want to *pause* a *long operation*. Surely that will just make it take longer. If you want the file to be written asynchronously then why not just use asynchronous file IO and await the result? – Eric Lippert Jul 23 '16 at 20:53
  • 1
    @EricLippert : This is for if the user of my application wants to pause it, because the operation might eat much system resources. – Visual Vincent Jul 23 '16 at 20:56

4 Answers4

3

I think, based on the description, I'd do this

'Class level.
Private BytesWritten As Long = 0
Private NotPaused As New Threading.ManualResetEvent(True)

The change in the variable name is fitting since this is how it would be used

    'Method (thread) level.
     While BytesWritten < [target file size]
        '...write 4096 byte buffer to file...

        NotPaused.WaitOne(-1)

        '...do some more stuff...
    End While

To make the loop pause do this

    NotPaused.Reset()

and to continue

    NotPaused.Set()
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
dbasnett
  • 11,334
  • 2
  • 25
  • 33
  • 1
    Thank you. This solution fits better since the `ManualResetEvent` is only "open" or "closed", apart from the `Semaphore` which seems to be opened for _x_ amount of calls. Now you also taught me a bit on how `ManualResetEvents` work! – Visual Vincent Jul 23 '16 at 21:29
2

In .NET there’s no reason to use Thread.Sleep besides trying to simulate lengthy operations while testing and / or debugging on an MTA thread as it will block.

Perhaps another option would be to use the TPL. Since you don't want to block you can use Task.Delay. As you probably know, a Task represents an asynchronous operation.

William Xifaras
  • 5,212
  • 2
  • 19
  • 21
1

I think that the more elegant way is to make the thread sleep indefinitely until it's awoken by another thread calling Thread.Interrupt on the first thread that's sleeping. There's a good example of this on with example code: Pausing and Resuming Threads.

Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
1

I might be misunderstanding what you're trying to achieve here, but from what I see, it seems like you're trying to block a thread until an IO task has finished. Semaphores would be the best bet here, instead of doing Thread.Sleep().

Most operating systems offer blocking semaphores that put a thread to sleep permanently until another thread wakes it up. You're probably better off utilizing them instead of constantly doing that check yourself.

Both Thread.Sleep() and blocking semaphores put the thread to sleep, but the latter does it perpetually until the resource has been freed (the semaphore has been signed). The former requires the thread to constantly wake up, check, and go back to sleep. The latter saves these execution cycles.

  • Sorry for being unclear. I'm not trying to block until an I/O operation has finished, I'm trying to pause the I/O operation. I basically write buffers of data to a file until all data has been written, since this might take some time I want to be able to pause that work. – Visual Vincent Jul 23 '16 at 20:33
  • Great answer! Short and easily understandable explanations! – Visual Vincent Jul 23 '16 at 21:06
  • I still like you answer very much, but I marked dbasnett's answer as the accepted one instead since it fits my usage better. A `ManualResetEvent` allows/blocks only a single call, while when using a `Semaphore` you have to specify _how many_ it should allow until it blocks. – Visual Vincent Jul 23 '16 at 21:32