在动态创建的多线程中维持参数值? (C#)

时间:2011-07-24 12:56:53

标签: c# asp.net multithreading thread-safety threadpool

我不能说我完全理解线程的概念,即使我读了很多文章,我有点厚,我想要的是线程安全参数。我正在向一个线程发送字符串参数,我正在使用ThreadPool.QueueUserWorkItem来启动,但我正在使用相同的线程再次使用另一个参数。

我想要它能够处理具有不同参数的不同线程,但它不稳定可能是因为我在调用第一个线程后正在更改参数字符串。我的直觉告诉我使用Lock但不知道如何以及在哪里......

哦,顺便说一句,这段代码的输出通常是3个使用最新参数的线程(200p的配置)

我用来调用我的线程的代码就是这个;

    processThread pt = new processThread();
    pt.fileName = AppDomain.CurrentDomain.BaseDirectory + "bin\\ffmpeg.exe";
    pt.filePath = Path.Combine(Vci.Core.Sandbox.UploaderControlSandboxPath, fileGuid);
    pt.vidPathHigh = AppDomain.CurrentDomain.BaseDirectory + "videos\\480p\\" + fileGuid + ".wmv";
    pt.vidPathMid = AppDomain.CurrentDomain.BaseDirectory + "videos\\360p\\" + fileGuid + ".wmv";
    pt.vidPathLow = AppDomain.CurrentDomain.BaseDirectory + "videos\\200p\\" + fileGuid + ".wmv";
    if (height >= 480) 
    {
        newHeight = (int)Math.Floor(480 * aspectRatio);
        initArgs = "-i " + pt.filePath + " -vcodec wmv2 -qscale 2 -s " + newHeight + "x480 -acodec wmav2 -ar 44100 -ab 128k -y \"" + pt.vidPathHigh + "\"";
        ThreadPool.QueueUserWorkItem(o => pt.callExecute(initArgs));
        newHeight = (int)Math.Floor(360 * aspectRatio);
        initArgs = "-i " + pt.filePath + " -vcodec wmv2 -qscale 4 -s " + newHeight + "x360 -acodec wmav2 -ar 44100 -ab 128k -y \"" + pt.vidPathMid + "\"";
        ThreadPool.QueueUserWorkItem(o => pt.callExecute(initArgs));
        newHeight = (int)Math.Floor(200 * aspectRatio);
        initArgs = "-i " + pt.filePath + " -vcodec wmv2 -qscale 6 -s " + newHeight + "x200 -acodec wmav2 -ar 44100 -ab 128k -y \"" + pt.vidPathLow + "\"";
    }

我的线程Class的代码就是这个;

    public class processThread
    {
    public string filePath { get; set; }
    public string fileName { get; set; }
    public string vidPathHigh { get; set; }
    public string vidPathMid { get; set; }
    public string vidPathLow { get; set; }
    public void callExecute(Object o)
    {
        try
        {
            executeProcess(fileName, o as string);
        }
        catch (ThreadAbortException abortException)
        {
            // do something
        }
    }

    private void executeProcess(string fileName, string arguments)
    {
        Process myProcess = new Process();
        myProcess.StartInfo.FileName = fileName;
        myProcess.StartInfo.Arguments = arguments;
        myProcess.StartInfo.UseShellExecute = false;
        myProcess.StartInfo.CreateNoWindow = false;
        myProcess.StartInfo.RedirectStandardOutput = false;
        try
        {
            myProcess.Start();
        }
        catch (Exception ex)
        {
            throw;
        }
        myProcess.WaitForExit();
        myProcess.Close();
    }
}

在此先感谢任何帮助表示赞赏!

3 个答案:

答案 0 :(得分:2)

问题在于您通过使用lambda表达式“捕获”initargs

您不应该以这种方式重用initargs。您的代码将更易读,更易于维护,您将避免此问题。

首先,使用两个不同的initargs实例:

string initArgsWithScaleTwo = // 
ThreadPool.QueueUserWorkItem(o => pt.callExecute(initArgsWithScaleTwo));
string initArgsWithScaleFour = //
ThreadPool.QueueUserWorkItem(o => pt.callExecute(initArgsWithScaleFour));    

其次,当你分配给initArgs时,会有很多不必要的重复。维护起来并不好玩。这应该让你开始更清晰的版本:

private string GetInitArgs(
    string filePath,
    int scale,
    int newHeight,
    string vidPathHigh,
    int scanLines
) {
    return "-i " + filePath + String.Format(" -vcodec wmv2 -qscale {0} -s ", scale) + newHeight + String.Format("x{0} -acodec wmav2 -ar 44100 -ab 128k -y \"" + pt.vidPathHigh + "\"", scanLines);
}

你可以做更多事情并使用String.Format来真正清理整个事情。

然后你可以说

string initArgsWithScaleTwoAnd480ScanLines = 
    GetInitArgs(
       pt.filePath,
       2,
       (int)Math.Floor(480 * aspectRatio,
       pt.vidPathHigh,
       480
    );

所有这一切,如果线程只是启动新进程,我不明白你为什么要使用线程。只需直接启动流程,等待它们全部完成。

答案 1 :(得分:0)

嗯,我不确定我是否明白你在问什么。 Process.Start通常不会阻止当前线程,因此您可以启动任意数量的新进程,因为您的系统可以从应用程序的单个线程中吞下...

答案 2 :(得分:0)

我不确定定义initArgs的位置,因此更改它并调用使用它的线程可能会导致一些问题。

但是我建议你看一下Joseph Albahari关于线程的free e-book。它是一个很好的资源,并为如何为各种线程场景设计代码提供了一些很好的建议。在您的情况下,您可能需要考虑Wait and Pulse模式。