在线程中执行时方法不起作用,否则起作用 - C#

时间:2010-08-30 03:27:58

标签: c# multithreading

我是C#的初学者,我想做以下事情:

Thread t = new Thread(new ThreadStart(this.play));
t.Start();

这是方法play

    private void play()
    {
        playSong("path\\to\\song.mp3");
    }

    private static void playSong(String path)
    {
        mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
        mciSendString("play MediaFile", null, 0, IntPtr.Zero);
    }

    [DllImport("winmm.dll")]
    private static extern long mciSendString(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);

当我执行这样的方法时:play();,不使用线程,歌曲播放完美,但如果我喜欢在第一段代码摘录中,它就不会播放。

我怀疑它发生是因为我需要在主线程中调用mciSendString方法。如果是这样,有人会告诉我该怎么做?或者告诉我如何使用线程使其工作?

感谢您的帮助。

- 从这里编辑 -

我不知道是否应该发布代码,因为它有点大,但我会减少它,以显示我想要做的事情:

我有一个Windows窗体应用程序,它启动一个套接字,当它开始时监听端口,它作为一个服务器。此服务器接收它将播放的歌曲的请求路径。如果我使用如下所示的play方法,表单崩溃,但应用程序仍然监听我的请求。我知道我必须在后台执行此操作,以便表单控件不会崩溃,我只是不知道更好的方法。

    //Constructor
    public Main()
    {
        InitializeComponent();
        play();
    }

play()是这样的:

    private void play()
    {
        //Does the socket initialization
        do
        {
        //...
                while (true)
                {
                    //Reads text from client
                    //The text contains a string, indicating the path to the song.
                    byte[] bytesFrom = new byte[10025];
                    networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
                    string dataFromClient = System.Text.Encoding.Default.GetString(bytesFrom);

                    //Plays the song from the received path
                    playSong(dataFromClient);

                    //...Do other stuff
                }
        } while (_serverOn);

        //Closes the socket connection
    }

    private static void playSong(String path)
    {
        mciSendString("open \"" + path + "\" type mpegvideo alias MediaFile", null, 0, IntPtr.Zero);
        mciSendString("play MediaFile", null, 0, IntPtr.Zero);
    }

3 个答案:

答案 0 :(得分:1)

我有一段时间有类似的问题......痛苦的屁股。

您正在进行跨线程操作,这是不安全的。这就是崩溃的原因。你对问题所在的地方绝对正确。

这是关于此线程操作http://msdn.microsoft.com/en-us/library/ms171728.aspx

的msdn文档

您需要为mciSendString =>添加委托定义mciSendStringCallBack

delegate void mciSendStringCallBack(string strCommand, StringBuilder strReturn, int iReturnLength, IntPtr hwndCallback);

private static void playSong(String path)中,您需要检查 InvokeRequired ,如果是,则需要实例化回调并调用它。

mciSendStringCallBack method = new mciSendStringCallBack(....); this.Invoke(method , new object[] { .....});

通过msdn网站上的示例,他们可以很好地演示它的工作原理。

-

您可能想尝试使用后台工作程序,它为您提供多线程的处理方式,更易于使用。

答案 1 :(得分:1)

我怀疑MCI功能可能需要运行消息循环。此外,MCI请求被解除阻塞,因此一旦调用MCI操作,您的线程就会死亡。您需要继续在该线程上运行消息循环(使用Application.Run)直到MCI完成(您将通过传递窗口句柄请求回调)。请参阅说明如何完成的this文章。

编辑:也许在新线程上启动的隐藏表单可以减少要完成的工作。但是你仍然需要从MCI接收回调来终止线程。

答案 2 :(得分:1)

上面接受的答案仍在UI线程上运行mciSendString。我需要将它从UI线程移开,因为它花费的时间太长(保存文件的时间> 200ms),所以我提出了这个解决方案:

var t = new Thread(Dispatcher.Run);
t.SetApartmentState(ApartmentState.STA);
t.IsBackground = true;
t.Start();
var d = Dispatcher.FromThread(t)

d.InvokeAsync(() => mciSendString(command, null, 0, IntPtr.Zero));