Thread构造函数?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thread构造函数?相关的知识,希望对你有一定的参考价值。
Thread thread1 = new Thread(t1, "加线程1");
Thread thread2 = new Thread(t1, "加线程2");
Thread thread3 = new Thread(t2, "减线程1");
Thread thread4 = new Thread(t2, "减线程2");
这几行代码什么意思?
程序代码里没有Thread类代码。应该是直接继承类库里的吧?
http://wenda.so.com/q/1373361565064540
这是那段代码的地址
没有参数的 std::thread 构造函数
【中文标题】没有参数的 std::thread 构造函数【英文标题】:std::thread constructor with no parameter 【发布时间】:2016-01-27 12:42:49 【问题描述】:根据cppreference.com,
std::thread
没有参数的构造函数表示:
创建不代表线程的新线程对象。
我的问题是:
-
为什么我们需要这个构造函数?如果我们使用这个构造函数创建一个
thread
,我们以后如何“分配”一个线程函数?
为什么我们没有一个“run(function_address)”方法,这样当不带参数构造时,我们可以为 thread
指定一个函数来“运行”。
或者,我们可以构造一个带有可调用参数(函数、函子等)的thread
,但稍后调用“run()”方法来实际执行线程。为什么std::thread
不是这样设计的?
【问题讨论】:
线程是可移动的,因此可以交换。 【参考方案1】:您的问题表明可能存在一些混淆,将 执行线程 的概念与 std::thread
类型清楚地分开,并将两者与“线程函数”。
std::thread
类型的对象可以与一个执行线程相关联,或者它可以是“空的”并且不引用任何执行线程。
标准 C++ 中没有“线程函数”这样的概念。通过将任何函数传递给std::thread
对象的构造函数,任何函数都可以在新的执行线程中运行。
为什么我们需要这个构造函数?
构造不涉及执行线程的空状态。您可能希望拥有一个类的成员变量 std::thread
,但不希望立即将其与执行线程相关联。。所以你默认构造它,然后启动一个新的执行线程,并将它与std::thread
成员变量相关联。或者你可能想这样做:
std::thread t;
if (some_condition)
t = std::thread func1, arg1 ;
else
auto result = some_calculation();
t = std::thread func2, arg2, result ;
默认构造函数允许创建对象t
,而无需启动新的执行线程直到需要。
如果我们使用这个构造函数创建一个线程,我们以后如何“分配”一个线程函数呢?
您使用“分配”来“分配”:-)
但是您没有为其分配“线程函数”,这不是std::thread
的用途。你为它分配另一个std::thread
:
std::thread t;
std::thread t2 func, args ;
t = std::move(t2);
考虑创建一个新的执行线程,而不是“分配一个线程函数”给某物。您不只是分配一个函数,这就是 std::function
的用途。您正在请求运行时创建一个新的执行线程,该线程将由std::thread
对象管理。
为什么我们没有一个“run(function_address)”方法,这样当不带参数构造时,我们可以指定一个函数来为那个线程“运行”。
因为你不需要它。您可以通过构造带有参数的std::thread
对象来启动新的执行线程。如果您希望该执行线程与现有对象相关联,则可以通过移动分配或交换来实现。
或者,我们可以构造一个带有可调用参数(函数、函子等)的线程,但稍后调用“run()”方法来实际执行该线程。为什么 std::thread 不是这样设计的?
为什么要这样设计?
std::thread
类型用于管理一个执行线程,该线程不持有供以后使用的可调用对象。如果您想创建一个可调用对象,以后可以在新的执行线程上运行,在 C++ 中有很多方法可以做到这一点(使用 lambda 表达式,或std::bind
,或@987654336 @,或std::packaged_task
,或自定义函子类型)。 std::thread
的工作是管理一个执行线程,在你想调用它之前不要持有一个可调用对象。
【讨论】:
【参考方案2】:提供了默认构造函数,以便可以创建“空”thread
对象。在构造所述对象时,并非所有thread
对象都将与执行线程相关联。考虑thread
是某个类型的成员并且该类型具有默认构造函数的情况。考虑另一种情况,thread
类型没有“挂起”线程的概念,即它不能在挂起状态下创建。
thread
类型没有某种“运行”方法,因为最初的设计决策 (IIRC) 之一是在 thread
对象和执行线程之间建立“强”关联.允许thread
s 被“移动”使这个意图更清晰(在我看来)。因此,将thread
对象的实例移动到“空”对象比尝试“运行”thread
更清晰。
可以想象,您可以创建一个提供“运行”方法的某种包装类,但我认为这可能是一个更窄的用例,并且可以通过@987654330 的 API 解决 @类。
【讨论】:
谢谢@Niall,但为什么最初的设计偏爱“强”关联?它有什么好处? 当时的很多讨论都是围绕在对象超出范围后如何处理“未连接”线程?鉴于对做什么没有真正的共识,因此调用std::terminate
的结果是因为它提供了“最安全”的结果。 IE。如果程序员打算将其从正在运行的线程中分离出来,那么他们需要对此进行明确说明,并且析构函数中的“连接”可能会导致意外死锁。【参考方案3】:
默认构造函数使您可以创建线程数组:
thread my_threads[4];
for (int i=0; i<4; i++)
thread temp(func,...);
my_threads[i]=move(temp);
使用默认构造函数创建的线程“成为”具有移动构造函数的“真实”线程。
如果您需要/喜欢,您可以将线程与标准容器一起使用。
【讨论】:
【参考方案4】:编辑:也许让我们先评论最后一部分:
3.2 为什么std::thread不是这样设计的?
我不知道究竟是为什么(肯定有优点和缺点 - 请参阅 Jonathan Wakely 的回答以获取有关其背后理性的更多详细信息),但似乎 c++11 std::thread
的建模更接近 pthreads比例如QT 或 Java 的 QThread/Thread
类,这可能是您困惑的根源。
关于你的其他问题:
1.1 为什么我们需要这个构造函数?
您可能想创建一个std::thread
变量,但不要直接启动线程(例如,类成员变量或静态数组的元素,如alangab 所示)。它与无需文件名即可创建的std::fstream
没有太大区别。
1.2 如果我们使用这个构造函数创建一个线程,我们以后如何“分配”一个线程函数?
例如:
std::thread myThread;
// some other code
myThread = std::thread(foo());
为什么我们没有一个“run(function_address)”方法,这样当不带参数构造时,我们可以指定一个函数来为那个线程“运行”。
我不知道为什么要这样设计,但我看不出run
方法与上述语法相比有什么好处。
3.1 或者,我们可以构造一个带有可调用参数(函数、函子等)的线程,但稍后调用“run()”方法来实际执行线程。
您可以通过创建 lambda 或 std::function
对象来模拟这一点,并在您想要运行该函数时创建线程。
auto myLambda = [=]foo(param1, param2);;
// some other code
std::thread myThread(myLambda);
如果您想使用您描述的语法,我建议您编写自己的 Thread
包装类(应该只需要几十行代码),它(可选)还可以确保线程是分离的或在破坏包装器时加入,在我看来,这是 std::thread
的主要问题。
【讨论】:
以上是关于Thread构造函数?的主要内容,如果未能解决你的问题,请参考以下文章