C++:不调用main函数中的join()函数是否可以执行线程?
C++ : Can a thread be executed without calling the join() function in the main function?
请帮我解决一个关于以下代码输出的简单问题。
我以为只有调用join()或detach()函数时才会执行线程
因此,我希望输出仅打印“暂停 2 秒结束,ID = 59306”,而不打印“暂停 1 秒” ended , ID = 10218”因为我以为只有thread 2会被执行,而thread 1会NOT 被执行。但是,我错了。
实际上,输出实际上打印了上面提到的两行,这意味着线程 1 和 2 都被执行了。是真的吗?
你能给我解释一下代码实际上是如何执行两个线程的吗?
============================
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended , ID = " << std::this_thread::get_id() << std::endl;
}
int main()
{
std::cout << "Spawning 2 threads...\n";
std::thread t1 (pause_thread,1);
std::thread t2 (pause_thread,2);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
//t1.join();
t2.join();
//t1.detach();
//t2.detach();
std::cout << "All threads joined!\n";
return 0;
}
实际输出:
Spawning 2 threads...
Done spawning threads. Now waiting for them to join:
pause of 1 seconds ended , ID = 10218
pause of 2 seconds ended , ID = 59306
All threads joined!
===================
更新:
感谢大家的评论和回答。
现在,我理解了我不正确的逻辑,因为我错误地认为只有在调用 join() 或 detach() 函数时才执行线程。
我意识到线程一创建就执行,不需要调用 join() 或 detach()。
加入():
在 main() 函数中,当我们在线程上调用 join() 后,main() 函数将被阻塞,直到线程完成。线程完成后,main() 函数将恢复,线程的输出将与 main() 函数的任何剩余输出一起显示。
分离():
在main()函数中,如果我们在一个线程上调用detach(),那么,main()函数和线程都可以运行并发,并且它们之间不会被阻塞,也不会相互依赖以任何方式。在这种情况下,如果 main() 函数在分离线程完成之前完成,那么我们只能看到 main() 函数的输出,而看不到分离线程的输出。但是,如果分离线程在 main() 函数完成之前完成,那么我们可以看到线程和 main() 函数的输出。
线程不是在对它们调用 .join()
时开始执行,而是在它们被构造时开始执行。
.join()
用于阻止调用线程的执行,直到被加入的线程完成执行。由于您观察到的原因,通常需要在 main()
退出之前加入所有线程:
当main()
到达return
语句时,剩下std::thread
个对象的范围。如果此时管理线程的 std::thread
上既没有调用 .join()
也没有调用 .detach()
,则 std::thread
的析构函数将调用 std::terminate()
,其中(默认情况下)中止整个程序的执行。
即使您分离线程而不是加入线程,当 main()
没有通过调用 .join()
阻塞足够长的时间并在线程完成输出之前退出时,也会出现问题.退出main()
后,静态存储时长对象被销毁。一个这样的对象是 std::cout
。当线程在等待后尝试通过 std::cout
输出时,它已经被破坏并且程序具有未定义的行为。
另请注意,分离 t1
和加入 t2
也不安全,尽管等待时间似乎表明了这一点。确切地安排线程执行的时间取决于操作系统。线程 t2
可能会在 t1
之前完成,在这种情况下,上述问题再次出现,导致程序再次出现未定义的行为。
请帮我解决一个关于以下代码输出的简单问题。
我以为只有调用join()或detach()函数时才会执行线程
因此,我希望输出仅打印“暂停 2 秒结束,ID = 59306”,而不打印“暂停 1 秒” ended , ID = 10218”因为我以为只有thread 2会被执行,而thread 1会NOT 被执行。但是,我错了。
实际上,输出实际上打印了上面提到的两行,这意味着线程 1 和 2 都被执行了。是真的吗?
你能给我解释一下代码实际上是如何执行两个线程的吗?
============================
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended , ID = " << std::this_thread::get_id() << std::endl;
}
int main()
{
std::cout << "Spawning 2 threads...\n";
std::thread t1 (pause_thread,1);
std::thread t2 (pause_thread,2);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
//t1.join();
t2.join();
//t1.detach();
//t2.detach();
std::cout << "All threads joined!\n";
return 0;
}
实际输出:
Spawning 2 threads...
Done spawning threads. Now waiting for them to join:
pause of 1 seconds ended , ID = 10218
pause of 2 seconds ended , ID = 59306
All threads joined!
===================
更新:
感谢大家的评论和回答。
现在,我理解了我不正确的逻辑,因为我错误地认为只有在调用 join() 或 detach() 函数时才执行线程。
我意识到线程一创建就执行,不需要调用 join() 或 detach()。
加入(): 在 main() 函数中,当我们在线程上调用 join() 后,main() 函数将被阻塞,直到线程完成。线程完成后,main() 函数将恢复,线程的输出将与 main() 函数的任何剩余输出一起显示。
分离(): 在main()函数中,如果我们在一个线程上调用detach(),那么,main()函数和线程都可以运行并发,并且它们之间不会被阻塞,也不会相互依赖以任何方式。在这种情况下,如果 main() 函数在分离线程完成之前完成,那么我们只能看到 main() 函数的输出,而看不到分离线程的输出。但是,如果分离线程在 main() 函数完成之前完成,那么我们可以看到线程和 main() 函数的输出。
线程不是在对它们调用 .join()
时开始执行,而是在它们被构造时开始执行。
.join()
用于阻止调用线程的执行,直到被加入的线程完成执行。由于您观察到的原因,通常需要在 main()
退出之前加入所有线程:
当main()
到达return
语句时,剩下std::thread
个对象的范围。如果此时管理线程的 std::thread
上既没有调用 .join()
也没有调用 .detach()
,则 std::thread
的析构函数将调用 std::terminate()
,其中(默认情况下)中止整个程序的执行。
即使您分离线程而不是加入线程,当 main()
没有通过调用 .join()
阻塞足够长的时间并在线程完成输出之前退出时,也会出现问题.退出main()
后,静态存储时长对象被销毁。一个这样的对象是 std::cout
。当线程在等待后尝试通过 std::cout
输出时,它已经被破坏并且程序具有未定义的行为。
另请注意,分离 t1
和加入 t2
也不安全,尽管等待时间似乎表明了这一点。确切地安排线程执行的时间取决于操作系统。线程 t2
可能会在 t1
之前完成,在这种情况下,上述问题再次出现,导致程序再次出现未定义的行为。