none
该如何使用concurrency::create_task? RRS feed

  • 问题

  • 感觉ppl的异步接口很清爽,试用了一下非常喜欢。其中concurrency::create_task接口的特性非常棒:

    void func(int n)
    {
        printf("%d\tTask thread: %lu\n", n, GetCurrentThreadId());
        concurrency::parallel_for(0, 10, [](int idx) {
            Sleep(1000);
            printf("Work thread: %lu\n", GetCurrentThreadId());
        });
    }

    int main() { printf("Main thread: %lu\n", GetCurrentThreadId()); int id = 1; concurrency::create_task([&id]() { func(id++); return id; }).then([](int id) { func(id++); return id; }).then([](int id) { func(id++); }).wait(); cout << "end...\n"; return 0; }

    任务异步执行,Stroe应用中then函数在UI线程中执行,直接更新UI。但是这有一个问题:用户关闭程序时(不特指UWP应用或Metro应用,包括mfc等任意使用c++编写的应用),可能后台线程没有执行完毕,导致后台线程依赖的资源提前释放,程序崩溃。

    于是我找到了concurrency::task_group,可以管理一系列后台线程,并在程序关闭前wait,保证后台线程结束后再释放资源。可是concurrency::task_group如何管理concurrency::create_task创建的任务?

    如果task_group做不到,那我就只能自己封装一个类,把create_task创建的对象放入一个map,关闭程序前统一wait了,这种使用方式是不是有点丑陋?

    create_task的then函数可以直接回调到UI线程,但是不能统一管理并在程序关闭前统一wait。task_group可以统一管理后台线程并在程序关闭前统一wait,但不能回调到UI线程,也不能使用逻辑更清晰的then函数链式回调。

    ………………为什么两种不能统一起来呢?



    • 已编辑 潇羽 2016年5月16日 5:17
    2016年5月16日 5:15

全部回复

  • Hi 潇羽

    感谢在msdn论坛发帖。

    task_group支持取消概念取消使你可以向所有活动任务发出信号,表示你要取消整个操作。取消还可以阻止尚未开始的任务开始。参考PPL中的取消操作

    详情参考文档:https://msdn.microsoft.com/zh-cn/library/dd492427.aspx#task-groups

    Best Regards,

    Sera Yu


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.


    • 已编辑 Baron Bi 2016年5月16日 8:56
    2016年5月16日 8:56
  • 请原谅我幼儿园没毕业的表达水准。其实需求是这样的,程序运行过程中,创建任务扔到后台线程跑,任务完成后更新响应的资源(可能是ui,也可能是别的);程序退出时,注意这里说的退出是指win32程序那种退出,退出之后没有后台没有墓碑,程序退出之后就完全销毁了。所以,接收到程序退出的消息后,必须在主线程阻塞等待所有后台线程完成(其实这里的等待跟取消所有后台效果是一样的,总之仍在运行的线程能够很快自然结束掉),否则就会造成资源释放后,后台线程又去使用已释放资源的悲剧,于是退出崩溃就发生了。

    concurrency::create_task的链式回调比较小清新,比较喜欢用,可以直接.then.then.then之类的,可是没找到ppl中有管理concurrency::create_task创建的任务的方法,于是只能自己封装一个管理类,以便程序退出时阻塞主线程等待后台线程完成(或者阻塞主线程取消所有后台线程,总之所有后台线程销毁前主线程是必须阻塞等待的。可以不用考虑store程序,只考虑传统的win32)。task_group可以实现统一管理任务和阻塞等待,但是不能then,所以才比较奇怪为什么两种不能统一,为什么没有管理concurrency::task<某种类型>的方法。

    2016年5月27日 9:42
  • “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?
    2016年5月31日 5:01
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。
    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?
    2016年5月31日 5:01
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。
    • 已编辑 潇羽 2016年6月6日 6:00 添加对mfc程序的说明
    2016年6月6日 5:55
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我测试的就是mfc窗口程序,测试了几百次无此现象,如果你确实遇到了此问题,而不是设想可能会出现此问题,请提供能够呈现问题的代码。

    确实出过这种崩溃问题,有些代码是不能贴到网上的。

    你说你一个不懂编程的凑什么热闹

    2016年6月7日 2:08
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我没测试过 MFC,但用 Win32 测试了一下。

    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        //这些是系统自动生成的代码
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
        LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadStringW(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
        HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));
        MSG msg;
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        //从这开始是我添加的代码
        OutputDebugStringW(L"\n现在开始退出\n");
        class Test
        {
        public:
            ~Test()
            {
                std::wostringstream stringStream;
                stringStream << L"\n退出已完成 | " << Count << L"\n";
                OutputDebugStringW(stringStream.str().c_str());
            }
            Test() {}
            std::atomic_uint Count = 0u;
        };
        auto test = new Test();
        for (auto i = 0u; i != 1000u; ++i)
        {
            concurrency::create_task([test]()
            {
                concurrency::wait(100u);
                ++test->Count;
            });
        }
        delete test;
    
        //最后这一句也是系统自动生成的
        return (int) msg.wParam;
    }

    运行结果是:

    现在开始退出

    退出已完成 | 227

    很明显我在异步线程全部结束之前就强行销毁了变量 test,但没有任何崩溃发生。即使我把代码改成这样:

    auto test = new Test();
    delete test;
    for (auto i = 0u; i != 1000u; ++i)
    {
        concurrency::create_task([test]()
        {
            concurrency::wait(100u);
            ++test->Count;
        });
    }

    仍然没有发生崩溃。你不妨自己动手试一下 MFC 中的情况,如果有问题可以贴出来。

    你觉得代码写成这样

    auto test = new Test(); delete test; for (auto i = 0u; i != 1000u; ++i) { concurrency::create_task([test]() { concurrency::wait(100u); ++test->Count; }); }

    以及这样

    auto test = new Test(); for (auto i = 0u; i != 1000u; ++i) { concurrency::create_task([test]() { concurrency::wait(100u); ++test->Count; }); } delete test;

    都没问题,我还能说什么呢

    其他语言或许可以,C++写这样的代码………………我没话了

    2016年6月7日 2:13
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我没测试过 MFC,但用 Win32 测试了一下。

    int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                         _In_opt_ HINSTANCE hPrevInstance,
                         _In_ LPWSTR    lpCmdLine,
                         _In_ int       nCmdShow)
    {
        //这些是系统自动生成的代码
        UNREFERENCED_PARAMETER(hPrevInstance);
        UNREFERENCED_PARAMETER(lpCmdLine);
        LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
        LoadStringW(hInstance, IDC_WIN32PROJECT1, szWindowClass, MAX_LOADSTRING);
        MyRegisterClass(hInstance);
        if (!InitInstance (hInstance, nCmdShow))
        {
            return FALSE;
        }
        HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT1));
        MSG msg;
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    
        //从这开始是我添加的代码
        OutputDebugStringW(L"\n现在开始退出\n");
        class Test
        {
        public:
            ~Test()
            {
                std::wostringstream stringStream;
                stringStream << L"\n退出已完成 | " << Count << L"\n";
                OutputDebugStringW(stringStream.str().c_str());
            }
            Test() {}
            std::atomic_uint Count = 0u;
        };
        auto test = new Test();
        for (auto i = 0u; i != 1000u; ++i)
        {
            concurrency::create_task([test]()
            {
                concurrency::wait(100u);
                ++test->Count;
            });
        }
        delete test;
    
        //最后这一句也是系统自动生成的
        return (int) msg.wParam;
    }

    运行结果是:

    现在开始退出

    退出已完成 | 227

    很明显我在异步线程全部结束之前就强行销毁了变量 test,但没有任何崩溃发生。即使我把代码改成这样:

    auto test = new Test();
    delete test;
    for (auto i = 0u; i != 1000u; ++i)
    {
        concurrency::create_task([test]()
        {
            concurrency::wait(100u);
            ++test->Count;
        });
    }

    仍然没有发生崩溃。你不妨自己动手试一下 MFC 中的情况,如果有问题可以贴出来。


    delete只是标记一段内存为不再使用,并不会真的把内存中的数据清零。所以delete之后,只要没有其他程序使用并修改该段内存,即使delete了,你也可以继续用。这能说明,可以继续使用delete掉的内存吗?
    2016年6月7日 2:28
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我测试的就是mfc窗口程序,测试了几百次无此现象,如果你确实遇到了此问题,而不是设想可能会出现此问题,请提供能够呈现问题的代码。

    确实出过这种崩溃问题,有些代码是不能贴到网上的。

    你说你一个不懂编程的凑什么热闹


    这里是技术交流论坛,不是地痞流氓漫骂的场所。既然你不喜欢让别人参与,请远离此论坛,这里非常不欢迎你这种人。而且从你的回复来看你对编程一知半解,因此在你眼里别人才都不懂编程。这里的论坛是开放、友好、互助的,你是不受欢迎的,请自觉离开。

    谩骂…………我谩骂了吗!!!呵呵……不懂编程硬凑什么热闹
    2016年6月8日 1:40
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我测试的就是mfc窗口程序,测试了几百次无此现象,如果你确实遇到了此问题,而不是设想可能会出现此问题,请提供能够呈现问题的代码。

    如果这样的代码都觉得没问题

    //MyClass类使用了一个全局内存池 #include "MyClass" int main() { 初始化全局内存池 MyClass* mc = new MyClass; 初始化线程池 while (true) { 各种操作 } //设置后台线程结束标志 //等待线程池结束 销毁全局内存池 }

    说你不懂编程冤枉你了?


    • 已编辑 潇羽 2016年6月8日 1:43
    2016年6月8日 1:41
  • 另外对于程序退出后的问题,你能否提供可重现问题的完整代码?即使在win32中我也无法重现你所说的这个问题。

    “程序退出前必须阻塞等待所有线程结束,然后销毁资源”这有什么不好理解的吗?不这么做有可能造成非法访问有什么问题吗?程序要退出了,资源销毁了,后台线程还在跑着,继续引用已经销毁的资源,程序崩了,不好理解?

    不能理解的是你是否确实遇到了程序崩溃问题?因为我们没有遇到过这种情况,无法重现你所说的这一现象。所以请提供可以重现这一崩溃现象的代码。按照C++标准库中的介绍,主线程在退出时会自动等待或终止所有子线程,所以按理说是不会出现“后台线程还在跑”这一情况的。根据C++标准库中的说明,只有被解离的线程才会有这一情况,但PPL中好像没有解离的线程。

    补充说明一下。因为我也不知道PPL是不是调用标准库,所以我也无法确定你所说的问题是不存在的,只不过我在实际使用和测试中没有发现也无法重现你所说的问题。因此希望你能提供可以重现问题的代码。

    也许是我没说明白,主线程都退出了还有什么好纠结的。我的意思是“主线程退出前阻塞等待后台线程退出”,请看如下的一个伪码

    //MyClass类使用了一个全局内存池
    #include "MyClass"
    
    int main()
    {
        初始化全局内存池
        MyClass* mc = new MyClass;
        初始化线程池
    
        while (true)
        {
            各种操作
        }
        
        设置后台线程结束标志
        等待线程池结束
        销毁全局内存池
    }

    这里的全局内存池只是为了说明问题,也可能是其他资源,总之,“全局内存池”这个资源是必须在主线程退出前销毁的,必须!后台线程使用了这个资源,所以,如果不等待后台线程退出,就销毁了该资源,后台线程仍在运行的话,就可能继续使用该资源,程序就崩了。

    别说使用引用计数什么的,不是所有的资源都可以让开发者随便控制的,特别是维护一些程序的时候。

    正确的做法当然是在程序退出前先停掉后台线程,再销毁资源,然后才能干净清爽的退出。

    控制台程序还好说,如果是mfc程序,响应退出的消息后,距离程序真正退出还有很长一段,后台线程使用已销毁的资源的概率是非常大的,所以在一个合适的位置阻塞等待后台线程结束是非常必要的。

    我测试的就是mfc窗口程序,测试了几百次无此现象,如果你确实遇到了此问题,而不是设想可能会出现此问题,请提供能够呈现问题的代码。

    如果这样的代码都觉得没问题

    //MyClass类使用了一个全局内存池 #include "MyClass" int main() { 初始化全局内存池 MyClass* mc = new MyClass; 初始化线程池 while (true) { 各种操作 } //设置后台线程结束标志 //等待线程池结束 销毁全局内存池 }

    说你不懂编程冤枉你了?



    搞不懂你在说什么,看清楚,这些烂代码是你自己写的,我写的代码从来没崩溃过,你的代码烂所以才崩溃。自己睁眼睛看看自己帖子的标题“该如何使用concurrency::create_task?”连如何使用都不知道,还好意思评价别人,到底谁不懂编程?自己那点水平还这么狂妄,你是来请教别人问题的吗?说什么代码不能贴到网上,不能贴你跑到开放论坛来干什么,去找微软的收费技术支持去啊,人家给你保密,而且态度特别好,回复特别及时,只要你缴费就行了。还有这里是互助论坛,你给过别人多少帮助?回答过多少问题?我看你这人可能有病,该干嘛干嘛去吧,别在这捣乱了。

    不懂装懂真可怕
    2016年6月15日 3:33