线程是在编译或运行时确定的吗?

时间:2017-11-26 07:40:45

标签: c++ multithreading

我只是问自己:当我在代码中制作线程池时 然后我编译代码,
编译后的代码是否有每个线程的副本?

如果我使用宏功能,并将其传递给线程,
这个宏是在编译期间扩展的吗?#34;我的想法"或在运行期间,
如果它在编译时为什么以下代码需要互斥:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <iostream>
namespace asio = boost::asio;
#define PRINT_ARGS(msg) do {\
boost::lock_guard<boost::mutex> lg(mtx); \
std::cout << '[' << boost::this_thread::get_id() \
<< "] " << msg << std::endl; \
} while (0)
int main() {
asio::io_service service;
boost::mutex mtx;

for (int i = 0; i < 20; ++i) {
service.post([i, &mtx]() {
PRINT_ARGS("Handler[" << i << "]");
boost::this_thread::sleep(
boost::posix_time::seconds(1));
});
}

boost::thread_group pool;
for (int i = 0; i < 4; ++i) {
pool.create_thread([&service]() { service.run(); });
}
pool.join_all();
}

这里的lock_guard使cout成为关键部分,虽然只有主线程会将帖子发布到io_service上 然后运行任务的线程将在已经制作的lamda函数的队列上工作&gt;&gt;&gt;&gt;这让我认为没有必要使用互斥锁?
这是正确的吗?

这里我将模拟编译期间的宏扩展:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <iostream>
namespace asio = boost::asio;


#define PRINT_ARGS(msg) do {\
boost::lock_guard<boost::mutex> lg(mtx); \
std::cout << '[' << boost::this_thread::get_id() \
<< "] " << msg << std::endl; \
} while (0)

int main() {
asio::io_service service;
boost::mutex mtx;

for (int i = 0; i < 20; ++i) {
service.post([i, &mtx]() {

//PRINT_ARGS("Handler[" << i << "]");//>>>>>this will be

do {\\
boost::lock_guard<boost::mutex> lg(mtx); \\
std::cout << '[' << boost::this_thread::get_id() \\
<< "] " << "Handler[" << i << "]" << std::endl; \\
} while (0)

boost::this_thread::sleep(
boost::posix_time::seconds(1));
});
}

boost::thread_group pool;
for (int i = 0; i < 4; ++i) {
pool.create_thread([&service]() { service.run(); });
}
pool.join_all();
}  

然后程序将按以下顺序进行:
1-主线程:make io_service instance
2-主线程:make mutex instance
3-主线程:make for循环20次,每次主线程发布一个任务&#34; lambda函数&#34;在本书中定义了这个代码,将此函数对象添加到io_service中的内部队列中 我的问题是:主线程是否将20个lambda函数对象添加到队列中,在这种情况下每个都有一定的值i 然后当新的4个线程开始工作时,他给它们线程函数&#34;运行&#34;根据同一本书逐一删除功能对象并逐个执行 在这种情况下:
线程1:删除lambda 1并使用自己的代码执行它作为具有唯一i的单独实例 线程2:删除lambda 2并使用自己的代码执行它作为具有唯一i的单独实例 线程3:删除lambda 3并使用自己的代码执行它作为具有唯一i的单独实例 线程4:删除lambda 4并使用自己的代码执行它作为具有唯一i的单独实例 然后再次线程一个lambda 5
这是基于我的理解,队列有20个函数对象作为lambda函数&#34;可以包装在某些包装器中#34;因此每个线程将采用单独的对象,因此在编译之后不需要互斥体&#34; 20内部汇编代码&#34;

但是如果队列中的任务只是引用相同的单个代码&#34;但是当它执行for循环时#34; ,那么它将需要互斥锁来防止2个线程同时访问关键代码 这个场景是代码符号在这里出现的吗?

1 个答案:

答案 0 :(得分:0)

宏总是在编译时扩展,但编译器只有非常基本的线程知识(主要是关于能够说某些变量是线程本地的)。

代码只会在磁盘映像或实际运行的内存副本中存在一次。

锁定PRINT_ARGS中的互斥锁可确保每个操作的消息完整打印而不会被另一个线程中断。 (否则你可能有一个操作开始打印它的消息,被另一个打印其消息的线程上的另一个操作打断,然后打印出第一个操作消息的剩余部分。)