栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++多线程学习01 对象生命周期和线程的退出与等待

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++多线程学习01 对象生命周期和线程的退出与等待

子线程:

void ThreadMain()
{
    cout << "begin sub thread main " << this_thread::get_id() << endl;
    for (int i = 0; i < 10; i++)
    {
        if (!is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
    cout << "end sub thread main " << this_thread::get_id() << endl;
}

main函数三种情况:
01:

int main(int argc, char* argv[])
{
{
thread th(ThreadMain);
}
getchar();
 return 0;
}

explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
        using _Tuple                 = tuple, decay_t<_Args>...>;
        auto _Decay_copied           = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
        constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{});

#pragma warning(push)
#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to
                                // extern C function under -EHc. Undefined behavior may occur
                                // if this function throws an exception. (/Wall)
        _Thr._Hnd =
            reinterpret_cast(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));
#pragma warning(pop)

        if (_Thr._Hnd) { // ownership transferred to the thread
            (void) _Decay_copied.release();
        } else { // failed to start thread
            _Thr._Id = 0;
            _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);
        }

这是因为在使用函数指针做为thread的构造函数的参数时,会生成一个句柄 _Thr._Hnd ,这个句柄的生命周期与主线程一致,当主线程结束时该句柄也会被释放掉,由于此时子线程还在运行,因此将会出错

02

int main(int argc, char* argv[])
{
{
thread th(ThreadMain);
th.detach(); }
  getchar();
 return 0;
}

用detach()使子线程与主线程分离,相当于将子线程变成一个守护线程,将其资源如句柄的生命周期交给子线程
java的守护线程:
守护线程,是指在程序运行时 在后台提供一种通用服务的线程,这种线程并不属于程序中不可或缺的部分。通俗点讲,任何一个守护线程都是整个JVM中所有非守护线程的"保姆"。

用户线程和守护线程几乎一样,唯一的不同之处在于如果用户线程已经全部退出运行,只剩下守护线程存在了,JVM也就退出了。因为当所有非守护线程结束时,没有了被守护者,守护线程也就没有工作可做,当然也就没有继续执行的必要了,程序就会终止,同时会杀死所有的"守护线程",也就是说只要有任何非守护线程还在运行,程序就不会终止

03

int main(int argc, char* argv[])
{
{
        thread th(ThreadMain);
        th.detach(); //子线程与主线程分离 守护线程
        //坑 :主线程退出后 子线程不一定退出,因此要注意子线程不要使用主线程中的变量
    }
  {thread th(ThreadMain);
        this_thread::sleep_for(chrono::seconds(1));//模拟业务1000ms
        is_exit = true; //通知子线程退出
        cout << "主线程阻塞,等待子线程退出" << endl;
        th.join(); 
        //为了提高运行效率,在主线程业务逻辑处理结束才阻塞主线程,而不是子线程一加进来就阻塞主线程
        cout << "子线程已经退出!" << endl;}
  getchar();
 return 0;
}

th.join()方法用于把子线程加入到主线程中,把主线程的CPU执行时间让子线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。在加入前CPU给两个线程都分的有时间片(线程是CPU调度的基本单位),再加入后这两个线程平分原本主线程的时间片。在std::thread t(func)后“某个”合适的地方调用,其作用是回收对应创建的线程的资源,避免造成资源的泄露。

用this_thread::sleep_for(chrono::seconds(1));来模拟业务1000ms,当主线程业务结束时需要使用is_exit = true;通知子线程结束,但由于时间片调度子线程不会一瞬间就结束,要使用th.join()来等待子线程结束,不然它的句柄被主线程释放了的话会出现问题。


可以看到创建了两个线程,由于并发的执行被显示在同一行了,
此外可以看到子线程中的in thread 0只显示了一行,与主线程业务逻辑运行时间吻合。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/989583.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号