tags:

views:

329

answers:

5

In C# I can perform a Console.Beep(). However, if you specify a duration of say 1000, or 1 second, it will not execute the next line of code until that second passes.

Is there any way possible to execute Console.Beep() in a non-blocking fashion so it will continue to beep and still continue executing the code below it while beeping?

+1  A: 

You can run Console.Beep in a separate thread.

Mark Byers
+3  A: 

You can use the following code to run Console.Beep() in another thread:

System.Threading.Thread thread = new System.Threading.Thread(
    new System.Threading.ThreadStart(
        delegate()
        {
            Console.Beep();
        }
    ));

thread.Start();
0xA3
+15  A: 

You can run it in a separate thread.

new Thread(() => Console.Beep()).Start();

I woke this morning to find flurry of comments on this answer. So I thought I would chime in with some other ideas.

The above can also be achieved running the thread on the Thread Pool, by using the following.

Action beep = Console.Beep;
beep.BeginInvoke((a) => { beep.EndInvoke(a); }, null);

The important thing in the above code is to call EndInvoke on your delegate if you use BeginInvoke otherwise you will experience memory leaks.

From MSDN:Important: Always call EndInvoke to complete your asynchronous call. http://msdn.microsoft.com/en-us/library/2e08f6yc(VS.80).aspx

Alternatively, you can use the dedicated Beep thread to have beeps run in the background when on demand without creating a new thread everytime or using the thread pool (see Simon Chadwick's comment). As a simple example, you could have the following. Notice that I pass 1 as the maxStackSize, this will ensure that the minimum (not 1, minimum) stack space is committed for this thread, see MSDN for more detail on this.

  class BackgroundBeep
  {
    static Thread _beepThread;
    static AutoResetEvent _signalBeep;

    static BackgroundBeep()
    {
      _signalBeep = new AutoResetEvent(false);
      _beepThread = new Thread(() =>
          {
            for (; ; )
            {
              _signalBeep.WaitOne();
              Console.Beep();
            }
          }, 1);
      _beepThread.IsBackground = true;
      _beepThread.Start();      
    }

    public static void Beep()
    {
      _signalBeep.Set();
    }
  }

With this, all you need to do to run a backround beep at anytime with out creating new threads is make the following call

BackgroundBeep.Beep();
Chris Taylor
+1 for a one liner
Earlz
Wow, 2MB+ of memory and some other system resources allocated for a beep!
Pop Catalin
Please don't spin a new thread to run a short lived method! This is as much of on anti pattern in threading as it could get.
Pop Catalin
@Pop Catalin: Do you have a link/reference for the memory overhead when starting a thread?
0xA3
@0xA3, The default stack size is 1MB for desktop applications and 256Kb for ASP.Net http://msdn.microsoft.com/en-us/library/5cykbwz4.aspx, so it's 1MB not 2MB afterall, although I've clearly read read somewhere recently about 2MB but I can't find it.
Pop Catalin
@Pop: you apparently have some belief that setting the "this page is reserved" bits for 128 8KB pages of virtual address space is really really expensive. Why would it be really expensive to set 128 bits? Exactly what do you believe reserving a million bytes of virtual address space entails? remember, that is not physical memory, this is *notes in a page table about where the pages would be in the VIRTUAL address space should you ever need them*. They're not mapped into physical memory until they're used, and they never are used. Can you explain why you think that this is a scarce resource?
Eric Lippert
If the application needs this (and possibly other) non-blocking functions, then you could create a dedicated thread when the app starts, and have it wait on a semaphore. When the app needs a beep, all it has to do is raise the semaphore. This way a new thread is not created for each beep. In addition, this background thread could wait on a queue of "command" objects, so it could do many different operations. In this case the app would push a "Beep, 1000, 200" command onto the queue, and the background thread would pop this off the queue and perform the operation.
Simon Chadwick
@Eric, stack pages are committed by the CLR, not just reserved. Joe Duffy's post: http://www.bluebytesoftware.com/blog/2007/03/10/TheCLRCommitsTheWholeStack.aspx
Hans Passant
@Hans Passant, thanks, that's exactly the link I was looking for but I didn't find it.@Eric Lippert, I don't think threads are a scarce resource but an expensive one, that's why the thread pool is the recommended approach for such scenarios. I think creating new threads is an abused technique in .Net, and shouldn't be considered to be the answer to any threading problem that needs to be solved. My 2c.
Pop Catalin
@All, I agree with many of the points raised in this discussion. When I answered, I was thinking very much along the lines of what Simon Chadwick is saying. And was fully intending to comeback and provide the OP with a small sample demonstrating how the thread can be reused by signaling an AutoResetEvent everytime a Beep is required. I did consider using the Thread Pool via, BeginInvoke but I *think* (please correct if wrong) the Thread Pool has a higher latency for kicking off the thread and of course with BeginInvoke requires that you call EndInvoke otherwise you leak memory.
Chris Taylor
Well I learned something new -- and astonishing -- today. I had no idea that we'd do this crazy thing of committing all that memory. Weird!
Eric Lippert
+6  A: 

You could use SoundPlayer.Play() and asynchronously annoy the user with something that sounds better than BEEP.

Hans Passant
+1 for annoying.
Aaronaught
+2  A: 

Here's a resource friendly way to play a beep asynchronously :

Action beep = Console.Beep;
beep.BeginInvoke(null, null); 
Pop Catalin
With this method, is it still possible to specify the two int parameters of beep? So you can set duration/pitch?
Siracuse
Action beep = () => Console.Beep(freq, dur); beep.BeginInvoke(null, null);
John Saunders