【问题标题】:c++ execute system function in threadc ++在线程中执行系统函数
【发布时间】:2020-08-12 16:46:01
【问题描述】:

当我在一个线程中执行系统时,什么也没有发生。有解决办法吗?

#include <iostream>
#include <Windows.h>

using namespace std;

void runffplay()
{
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    system(_cmd);
}


CloseHandle(CreateThread(0, 0, (PTHREAD_START_ROUTINE)runffplay, 0, 0, 0));

【问题讨论】:

  • 注意:system 接近于最糟糕的方式,您可以从程序中运行另一个可执行文件。您对其他进程的环境的控制非常有限,并且捕获它的输出的方法也非常有限。这是一个安全噩梦。不要使用system,永远不要使用。
  • 您是否尝试过使用非常简单的方法(例如启动记事本)?如果您在runffplay 内放置一个诊断打印,会打印诊断消息吗?您可以做很多事情来帮助缩小问题范围,或者回答您自己的问题,或者将其变成一个更好的问题。
  • 我不是 Win32 编程大师,所以我可能会遗漏一些小细节,但 void runffplay() 不应该是 void runffplay(void *) 吗? Looks like I'm a little wrong。应该是DWORD runffplay(void *)
  • Quoiting MS's documentation: 在创建线程时不要用void返回类型声明这个回调函数并将函数指针转换为LPTHREAD_START_ROUTINE。执行此操作的代码很常见,但它可能会在 64 位 Windows 上崩溃。 阅读文档以查看它们是否明确告诉您不要做您正在做的事情总是好的。

标签: c++


【解决方案1】:

您的runffplay() 函数签名错误,因此您最终会破坏线程的调用堆栈。阅读CreateThread()ThreadProc 文档。

另外,您没有进行任何错误处理。

试试类似的方法:

#include <iostream>
#include <cstdlib>
#include <Windows.h>

DWORD WINAPI runffplay(LPVOID)
{
    // instead of system(), consider using exec..(), or CreateProcess() directly...
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    int ret = std::system(_cmd);
    std::cout << "system() returned " << ret << std::endl;
    return 0;
}

HANDLE hThread = CreateThread(NULL, 0, runffplay, NULL, 0, NULL);
if (!hThread) {
    DWORD err = GetLastError();
    std::cerr << "CreateThread() failed with error " << err << std::endl;
}
else {
    ...
    CloseHandle(hThread);
}

否则,请直接使用std::thread 而不是CreateThread()

#include <iostream>
#include <thread>
#include <cstdlib>

void runffplay()
{
    // instead of system(), consider using exec..(), or CreateProcess() directly...
    const char* _cmd = "ffplay -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"";
    int ret = std::system(_cmd);
    std::cout << "system() returned " << ret << std::endl;
}

std::thread thrd;

try {
    thrd = std::thread(runffplay);
}
catch (const std::system_error &e) {
    std::cerr << "thread failed with error " << e << std::endl;
}

...

if (thrd.joinable()) {
    thrd.join();
}

【讨论】:

  • 我还没有理解在线程中运行system 的意义。为什么不直接使用CreateProcess
  • 好吧,也许 OP 的 real 代码中的线程比调用system() 做得更多。或者,也许 OP 想要等待启动的进程完成,而不阻塞应用程序的其余部分。我们不知道,所以我们不要推测。从工作线程启动进程是完全合法的操作。
【解决方案2】:

使用CreateProcess得到预期的结果

#include <iostream>
#include <Windows.h>

using namespace std;

HWND ffplayw = 0;

void SetWallpaper()
{
    while (ffplayw == 0)
    {
        ffplayw = FindWindowW(L"SDL_app", 0);
        Sleep(10);
    }
}

int main()
{
    STARTUPINFO info = { sizeof(info) };
    PROCESS_INFORMATION processInfo;
    if (CreateProcess(L"D:\\my-tools\\ffmpeg\\bin\\ffplay.exe",
        (LPWSTR)L" -fs -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"",
        0, 0, 0, 0, 0, 0, &info, &processInfo))
    {
        // WaitForSingleObject(processInfo.hProcess, INFINITE);
        CloseHandle(processInfo.hProcess);
        CloseHandle(processInfo.hThread);
        Sleep(500);
        SetWallpaper();
    }
    return 0;
}

这也可以:

CreateProcess(
        L"C:\\Windows\\System32\\cmd.exe",
        (LPWSTR)L" /c ffplay -loop 0  \"D:\\dynamic wallpaper\\1.mp4\"",
        0, 0, 0, 0, 0, 0, &info, &processInfo)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    • 2022-06-15
    • 2023-03-08
    • 1970-01-01
    • 2013-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多