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

发布于 2024-11-25 14:17:08 字数 2777 浏览 0 评论 0原文

我不能说我完全理解线程的概念,即使我读了很多关于它的文章,我有点厚,我想要的是线程安全参数。我正在将字符串参数发送到一个线程,我正在使用 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 + "\"";
    }

我的线程类的代码是这样的;

    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();
    }
}

预先感谢任何帮助!

I can't say i fully understood the concept of threads even i read so many articles over it, i'm a bit thick and what i want is thread safe parameters. I'm sending string arguments to a thread that i'm using ThreadPool.QueueUserWorkItem to start but i'm using the same thread just after it again with another arguments.

What i want from it to be able to process different threads with different arguments but its not stable probably because i'm changing the parameter string just after calling the first thread. My instincts tell me to use Lock but don't know how to and where..

Oh btw the output of this code is usually 3 threads working with the latest parameter (which is configurations for 200p)

The code i use to call my thread is this;

    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 + "\"";
    }

And code to my thread Class is this;

    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();
    }
}

Thanks in advance any help is appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

心是晴朗的。 2024-12-02 14:17:08

问题是您正在通过使用 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
    );

综上所述,如果线程只是启动新进程,我根本不明白你为什么要使用线程。只需直接启动进程,然后等待它们全部完成即可。

The issue is that you are "capturing" initargs via the use of the lambda expression.

You shouldn't be reusing initargs in this way. Your code will be more readable and easier to maintain, and you will avoid this problem.

So, first, use two different instances of initargs:

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

Second, there's a lot of needless repetition when you assign to initArgs. That's not fun to maintain. This should get you started on a clearer version:

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);
}

You can do more and use String.Format to really clean the whole thing up.

Then you can say

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

All that said, I don't understand why you are using threads at all if the threads are merely starting new processes. Just start the processes directly, and wait for them all to finish.

九厘米的零° 2024-12-02 14:17:08

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

Hm, I am not sure if I understand what you are asking. Process.Start normally does not block current thread, so you can start as many new processes as your system can swallow from single thread of your application...

十六岁半 2024-12-02 14:17:08

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

但我建议您查看 Joseph Albahari 关于线程的免费电子书。这是一个很好的资源,并提供了一些关于如何为各种线程场景设计代码的好建议。对于您的情况,您可能需要考虑等待和脉冲模式。

I'm not sure where initArgs is defined, so changing that and calling threads which use it could lead to some problems.

But I'd recommend you look at Joseph Albahari's free e-book on Threading. It's an excellent resource and provides some good suggestions on how to design your code for various threading scenarios. In your case, you may want to consider the Wait and Pulse pattern.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文