单线程的解法
如下:
#include <iostream>
using namespace std;
static bool isPrime(int num)
{
if (num == 1)
{
return false;
}
if ((num == 2) || (num == 3))
{
return true;
}
int mod = num % 6;
if ((mod != 1) && (mod != 5))
{
return false;//不是6的倍数±1的,都不是质数。
}
else
{
for(int j = 2; j * j <= num; ++j)
{
if (num % j == 0)
{
return false;
}
}
return true;
}
}
int main()
{
int cnt = 0;
for(int i = 0; i <= 50000000; ++i)
{
if(isPrime(i))
{
++cnt;
}
}
cout << "cnt is " << cnt << endl; // 3001134,单线程时间是48秒
return 0;
}
结果是:
cnt is 3001134
real 0m48.490s
user 0m47.457s
sys 0m0.235s
可以看到单线程情况下,实际运行时间是48秒,约等于用户态占的时间和系统态占的时间之和。
我的Mac是4核的,此时只用了一个核来运行代码。
多线程的解法
需要使用的编译方法是
g++ -std=c++11 -pthread xxx.cpp
time a.out
-pthread 是一个编译选项,它用于启用 C++ 中的线程支持。
在 C++ 中,使用多线程需要在编译时链接线程库。-pthread 选项告诉编译器在链接阶段链接到 POSIX 线程库( pthread ),以便你可以在代码中使用线程相关的功能。
没有 -pthread 选项,你可能无法在代码中使用多线程,或者可能会遇到链接错误。
当你使用 -pthread 选项时,编译器会将线程库的代码包含到你的程序中,并生成可以使用线程的可执行文件。
当然可以通过修改别名alias的方式,简化一下。具体步骤如下:
vi ~/.bash_profile
在打开的文件中,您可以添加类似如下的内容来设置别名:
alias g++='g++ -std=c++11 -pthread'
多线程的代码如下:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
static bool isPrime(int num)
{
if (num == 1)
{
return false;
}
if ((num == 2) || (num == 3))
{
return true;
}
int mod = num % 6;
if ((mod != 1) && (mod != 5))
{
return false;//不是6的倍数±1的,都不是质数。
}
else
{
for(int j = 2; j * j <= num; ++j)
{
if (num % j == 0)
{
return false;
}
}
return true;
}
}
int cnt = 0;
mutex mtx;
void worker(int left, int right)
{
unique_lock<mutex> lckBegin(mtx);//打印要加锁,否则线程间有干扰
cout << this_thread::get_id() << ": begin()" << endl;
lckBegin.unlock();
for(int i = left; i < right; ++i)
{
if (isPrime(i))//该函数不能放在锁里,否则严重影响效率。
{
unique_lock<mutex> lck(mtx);
++cnt;//不加锁结果会错误
lck.unlock();
}
}
unique_lock<mutex> lckEnd(mtx);
cout << this_thread::get_id() << ": end()" << endl;
lckEnd.unlock();
}
int main()
{
const int batch = 5000000;//5百万
thread* trr[10];
for(int i = 0, j = 1; i < 10; ++i, j += batch)
{
trr[i] = new thread(worker, j, j + batch);
}
for(int i = 0; i < 10; ++i)
{
trr[i]->join();
}
for(auto x : trr)
{
delete x;
}
cout << "cnt is " << cnt << endl; // 3001134
return 0;
}
结果是:
zhanghaodeMacBook-Pro:cpp_excise zhanghao$ time ./a.out
0x70000a3e7000: begin()
0x70000a46a000: begin()
0x70000a7ff000: begin()
0x70000a882000: begin()
0x70000a5f3000: begin()
0x70000a676000: begin()
0x70000a6f9000: begin()
0x70000a77c000: begin()
0x70000a4ed000: begin()
0x70000a570000: begin()
0x70000a3e7000: end()
0x70000a46a000: end()
0x70000a4ed000: end()
0x70000a570000: end()
0x70000a5f3000: end()
0x70000a676000: end()
0x70000a6f9000: end()
0x70000a77c000: end()
0x70000a7ff000: end()
0x70000a882000: end()
cnt is 3001134
real 0m13.397s
user 1m21.319s
sys 0m0.381s
real 指实际运行时间,为13秒(每个核的大概时间)。
用户态时间为81秒。
我的Mac是四核的。可以看到,单个核所用的时间是用户态时间的大约1/4~1/5。