C++ 11发布之前,C++并没有对多线程编程的专门支持,C++ 11通过标准库引入了对多线程的支持,大大方便了程序员的工作,本篇我们对这部分进行简要的介绍。需要说明的是,C++ 11标准库内部包裹了pthread库,因此,编译程序的时候需要加上-lpthread连接选项.
#include
#include
#include
关键点
a. C++ 11中创建线程非常简单,使用std::thread类就可以,thread类定义于thread头文件,构造thread对象时传入一个可调用对象作为参数(如果可调用对象有参数,把参数同时传入),这样构造完成后,新的线程马上被创建,同时执行该可调用对象;
b. 用std::thread默认的构造函数构造的对象不关联任何线程;判断一个thread对象是否关联某个线程,使用joinable()接口,如果返回true,表明该对象关联着某个线程(即使该线程已经执行结束);
c. "joinable"的对象析构前,必须调用join()接口等待线程结束,或者调用detach()接口解除与线程的关联,否则会抛异常;
d. 正在执行的线程从关联的对象detach后会自主执行直至结束,对应的对象变成不关联任何线程的对象,joinable()将返回false;
e. std::thread没有拷贝构造函数和拷贝赋值操作符,因此不支持复制操作(但是可以move),也就是说,没有两个 std::thread对象会表示同一执行线程;
f. 容易知道,如下几种情况下,std::thread对象是不关联任何线程的(对这种对象调用join或detach接口会抛异常):
默认构造的thread对象;
被移动后的thread对象;
detach 或 join 后的thread对象;
这个程序创建了两个线程,分别对变量num进行了10000次++操作,由于两个线程同时运行,++num也没有加锁保护,所以最后的输出结果在10000到20000之间,有一定随机性,也证明了++num不是原子操作;
常做多线程编程的人一定对mutex(互斥)非常熟悉,C++ 11当然也支持mutex,通过mutex可以方便的对临界区域加锁,std::mutex类定义于mutex头文件,是用于保护共享数据避免从多个线程同时访问的同步原语。它提供了lock,try_lock,unlock等几个接口,功能如下:
调用方线程从成功调用lock()或try_lock()开始,到unlock()为止占有mutex对象;
线程占有mutex时,所有其他线程若试图要求mutex的所有权,则将阻塞(对于 lock 的调用)或收到false返回值(对于 try_lock );
调用方线程在调用 lock 或 try_lock 前必须不占有mutex。
我们用mutex改写上面的例子,达到两个线程不会同时++num的目的,改写如下:
经过mutex对++语句的保护,使同一时刻,只可能有一个线程对num变量进行++操作,因此,这段程序的输出必然是20000。
mutex和thread一样,不可复制(拷贝构造函数和拷贝赋值操作符都被删除),而且,mutex也不可移动;
备注:
a.操作系统提供mutex可以设置属性,C++11根据mutext的属性提供四种的互斥量,分别是
b.mutex成员函数加锁解锁
c. mutex RAII式的加锁解锁
很容易想到,mutex的lock和unlock必须成对调用,lock之后忘记调用unlock将是非常严重的错误,再次lock时会造成死锁。有时候一段程序中会有各种出口,如return,continue,break等等语句,在每个出口前记得unlock已经加锁的mutex是有一定负担的,而假如程序段中有抛异常的情况,就更为隐蔽棘手,C++ 11提供了更好的解决方案,对的,RAII,本系列文章多次提到RAII,想必大家应该不陌生。
类模板std::lock_guard是mutex封装器,通过便利的RAII机制在其作用域内占有mutex。
创建lock_guard对象时,它试图接收给定mutex的所有权。当程序流程离开创建lock_guard对象的作用域时,lock_guard对象被自动销毁并释放mutex,lock_guard类也是不可复制的。
一般,需要加锁的代码段,我们用{}括起来形成一个作用域,括号的开端创建lock_guard对象,把mutex对象作为参数传入lock_guard的构造函数即可,比如上面的例子加锁的部分,我们可以改写如下:
进入作用域,临时对象guard创建,获取mutex控制权(构造函数里调用了mutex的lock接口),离开作用域,临时对象guard销毁,释放了mutex(析构函数里调用了unlock接口),这是对mutex的更为安全的操作方式(对异常导致的执行路径改变也有效),大家在实践中应该多多使用;
C++11 std::unique_lock与std::lock_guard区别及多线程应用实例
C++多线程编程中通常会对共享的数据进行写保护,以防止多线程在对共享数据成员进行读写时造成资源争抢导致程序出现未定义的行为。通常的做法是在修改共享数据成员的时候进行加锁--mutex。在使用锁的时候通常是在对共享数据进行修改之前进行lock操作,在写完之后再进行unlock操作,进场会出现由于疏忽导致由于lock之后在离开共享成员操作区域时忘记unlock,导致死锁。
针对以上的问题,C++11中引入了std::unique_lock与std::lock_guard两种数据结构。通过对lock和unlock进行一次薄的封装,实现自动unlock的功能。
std::mutex mut;
void insert_data()
{
std::lock_guard lk(mut);
queue.push_back(data);
}
void process_data()
{
std::unqiue_lock lk(mut);
queue.pop();
}
std::unique_lock 与std::lock_guard都能实现自动加锁与解锁功能,但是std::unique_lock要比std::lock_guard更灵活,但是更灵活的代价是占用空间相对更大一点且相对更慢一点。
std::unique_lock 的构造函数的数目相对来说比 std::lock_guard 多,其中一方面也是因为 std::unique_lock 更加灵活,从而在构造 std::unique_lock 对象时可以接受额外的参数。总地来说,std::unique_lock 构造函数如下:
default (1) | |
---|---|
locking (2) | |
try-locking (3) | |
deferred (4) | |
adopting (5) | |
locking for (6) | |
locking until (7) | |
copy [deleted] (8) | |
move (9) | |
下面我们来分别介绍以上各个构造函数:
(1) 默认构造函数
新创建的 unique_lock 对象不管理任何 Mutex 对象。
(2) locking 初始化
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞。
(3) try-locking 初始化
新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.try_lock() 对 Mutex 对象进行上锁,但如果上锁不成功,并不会阻塞当前线程。
(4) deferred 初始化
新创建的 unique_lock 对象管理 Mutex 对象 m,但是在初始化的时候并不锁住 Mutex 对象。 m 应该是一个没有当前线程锁住的 Mutex 对象。
(5) adopting 初始化
新创建的 unique_lock 对象管理 Mutex 对象 m, m 应该是一个已经被当前线程锁住的 Mutex 对象。(并且当前新创建的 unique_lock 对象拥有对锁(Lock)的所有权)。
(6) locking 一段时间(duration)
新创建的 unique_lock 对象管理 Mutex 对象 m,并试图通过调用 m.try_lock_for(rel_time) 来锁住 Mutex 对象一段时间(rel_time)。
(7) locking 直到某个时间点(time point)
新创建的 unique_lock 对象管理 Mutex 对象m,并试图通过调用 m.try_lock_until(abs_time) 来在某个时间点(abs_time)之前锁住 Mutex 对象。
(8) 拷贝构造 [被禁用]
unique_lock 对象不能被拷贝构造。
(9) 移动(move)构造
新创建的 unique_lock 对象获得了由 x 所管理的 Mutex 对象的所有权(包括当前 Mutex 的状态)。调用 move 构造之后, x 对象如同通过默认构造函数所创建的,就不再管理任何 Mutex 对象了。
综上所述,由 (2) 和 (5) 创建的 unique_lock 对象通常拥有 Mutex 对象的锁。而通过 (1) 和 (4) 创建的则不会拥有锁。通过 (3),(6) 和 (7) 创建的 unique_lock 对象,则在 lock 成功时获得锁。
std::mutex mtx_syn;
std::condition_variable cv_syn;
std::condition_variable cv_syn_1;
bool ready = false;
void threadA(int id) {
while (1)
{
std::unique_lock lck(mtx_syn);
while (!ready) cv_syn.wait(lck);
// ...
std::cout << "thread " << id << '\n';
Sleep(500);
cv_syn.notify_all(); //cpu 轮询执行 所有被唤醒的线程。
cv_syn.wait(lck);
}
}
void threadB(int id) {
while (1)
{
//新创建的 unique_lock 对象管理 Mutex 对象 m,并尝试调用 m.lock() 对 Mutex 对象进行上锁,如果此时另外某个 unique_lock 对象已经管理了该 Mutex 对象 m,则当前线程将会被阻塞
std::unique_lock lck(mtx_syn);
while (!ready) cv_syn.wait(lck);
// ...
std::cout << "thread " << id << '\n';
Sleep(500);
cv_syn.notify_all();
cv_syn.wait(lck);
}
}
void threadC(int id) {
while (1)
{
std::unique_lock lck(mtx_syn);
while (!ready) cv_syn_1.wait(lck);
// ...
std::cout << "thread " << id << '\n';
Sleep(500);
cv_syn_1.notify_all();
cv_syn_1.wait(lck);
}
}
void go()
{
std::unique_lock lck(mtx_syn);
ready = true;
cv_syn.notify_one();
}
//线程同步
std::thread threads[5];
// spawn 10 threads:
//for (int i = 0; i<5; ++i)
// threads[i] = std::thread(print_id, i);
threads[0] = std::thread(threadA, 0);
threads[1] = std::thread(threadB, 1);
threads[2] = std::thread(threadC, 2); //该线程 与 0, 1 无关,不影响 0,1 线程的同步,因为用的不是一个 condition_variable
std::cout << "2 threads ready to race...\n";
go(); // go!
for (auto& th : threads) th.join();
#include
#include
std::thread::id main_thread_id = std::this_thread::get_id();
void hello()
{
std::cout << "Hello Concurrent World\n";
if (main_thread_id == std::this_thread::get_id())
std::cout << "This is the main thread.\n";
else
std::cout << "This is not the main thread.\n";
}
void pause_thread(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main() {
std::thread t(hello);
std::cout << t.hardware_concurrency() << std::endl;//可以并发执行多少个(不准确)
std::cout << "native_handle " << t.native_handle() << std::endl;//可以并发执行多少个(不准确)
t.join();
std::thread a(hello);
a.detach();
std::thread threads[5]; // 默认构造线程
std::cout << "Spawning 5 threads...\n";
for (int i = 0; i < 5; ++i)
threads[i] = std::thread(pause_thread, i + 1); // move-assign threads
std::cout << "Done spawning threads. Now waiting for them to join:\n";
for (auto &thread : threads)
thread.join();
std::cout << "All threads joined!\n";
}
多线程使用实例:
#include
#include
#include "../data300w/util/Util.h"
#include "cunpd.hpp"
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
using namespace glasssix;
#define ZOOM_ 1.0
#define SIZE 96
extern void splitString(const string& s, vector& v, const string& c);
template
Type stringToNum(const string& str)
{
istringstream iss(str);
Type num;
iss >> num;
return num;
}
void writeHistoFile(std::string filePath, vector & densi_data)
{
if (filePath == "" || densi_data.size() == 0)
{
return;
}
ofstream in;
in.open(filePath, ios::app); //ios::trunc
int length = densi_data.size();
for (int i = 0; i < length; i++)
{
string dataline = to_string(densi_data[i]);
in << dataline << "\n";
}
in.close();
}
float getHorizontal(LandMark &landmark)
{
float tan_theta = (landmark.points[1].y - landmark.points[0].y) / (landmark.points[1].x - landmark.points[0].x);
float theta = atan(tan_theta);
return theta * 180 / 3.1415926;
}
void showHistogram(vector & hor_data)
{
int densi[60] = { 0 };
int length = hor_data.size();
for (int i = 0; i < length; i++)
{
if (floor((hor_data[i] + 30)) >= 0 && floor((hor_data[i] + 30)) < 60)
{
densi[(int)floor((hor_data[i] + 30))]++;
}
if (floor((hor_data[i] + 30)) < 0)
{
densi[0]++;
}
else if (floor((hor_data[i] + 30)) >= 60)
{
densi[60]++;
}
}
string density_text = "D:\\UMD\\density_text.txt";
vectordensity_data(densi, densi + 60);
writeHistoFile(density_text, density_data);
Mat histImg;
histImg.create(1000, 1600, CV_8UC3);
histImg.setTo(0);
int offset = 10;
for (int i = 0; i < 60; i++)
{
double tmpCount = densi[i];
rectangle(histImg, Point2f(offset + i * 25, 1000), Point2f(offset + i * 25, 1000 - tmpCount / 15.0), Scalar::all(255), -1); //画出直方图
putText(histImg, to_string(i - 29), Point2f(offset + i * 25 + 3, 1000 - 3), 0.3, 0.3, Scalar(0, 0, 255));
Point2f pt0;
pt0.x = offset + i * 25;
pt0.y = 1000 - densi[i] / 15.0;
Point2f pt1;
pt1.x = offset + (i + 1) * 25;
pt1.y = 1000 - densi[i + 1] / 15.0;
line(histImg, pt0, pt1, Scalar(255, 0, 0), 1); //连接直方图的顶点
}
imshow("hist", histImg);
waitKey(0);
}
void getDatahor(string file1, vector & hor_data)
{
int mark_num = 5;
DataPrepareUtil dpu;
vector data;
dpu.readFileData(file1, data, mark_num);
int length = data.size();
for (int i = 0; i < length; i++)
{
float hor = getHorizontal(data[i]);
hor_data.emplace_back(hor);
}
}
void rotation(float theta, Mat &img, Mat &dst, Size img_size, LandMark &landmark, int mark_num)
{
//rotation
Mat mat = img;
Point2f center(img_size.width / 2, img_size.height / 2);
double angle = theta;
Mat rot = getRotationMatrix2D(center, angle, 1);
Rect bbox = RotatedRect(center, mat.size(), angle).boundingRect();
cv::warpAffine(mat, dst, rot, bbox.size());
for (int j = 0; j < mark_num; j++)
{
float theta = -3.1415926 / (180 / angle);
float x1 = landmark.points[j].x - rot.at(1, 2);
float y1 = landmark.points[j].y - rot.at(0, 2);
landmark.points[j].x = x1 * cos(theta) - y1 * sin(theta);
landmark.points[j].y = x1 * sin(theta) + y1 * cos(theta);
//circle(dst, Point(x, y), 2, Scalar(255, 0, 0));
}
//cv::imshow("dst", dst);
//cv::waitKey(0);
}
void augment_data(string img_path, string img_text, string result_path, string result_text)
{
DataPrepareUtil dpu;
int mark_num = 5;
srand((unsigned)time(NULL));
vector data;
dpu.readFileData(img_text, data, mark_num);
vector rotation_data;
vector hor_data;
getDatahor(img_text, hor_data);
int length = hor_data.size();
for (int i = 0; i < length; i++)
{
if (hor_data[i] > 0 && hor_data[i] < 3)
{
Mat dst;
Mat img = imread(img_path + data[i].fileName);
LandMark landmark(data[i]);
rotation(25, img, dst, Size(96, 96), landmark, mark_num);
rotation_data.push_back(landmark);
}
}
}
bool getFaceRect(cunpd &pd, int model_id, Mat &dstImg, LandMark & landmark, Rect & rect)
{
const int widths = dstImg.cols;
const int heights = dstImg.rows;
vector face = pd.detect(dstImg, model_id, 48);
int length = face.size();
if (length == 0)
{
cout << "not found face ." << endl;
}
for (int j = 0; j < length; j++)
{
if (face[j].score > 15)
{
rect = face[j].rect;
if (landmark.points[0].x > rect.x && landmark.points[0].x < rect.x + rect.width
&& landmark.points[0].y > rect.y && landmark.points[0].y < rect.y + rect.height
&&landmark.points[12].x > rect.x && landmark.points[12].x < rect.x + rect.width
&& landmark.points[12].y > rect.y && landmark.points[12].y < rect.y + rect.height
&&landmark.points[16].x > rect.x && landmark.points[16].x < rect.x + rect.width
&& landmark.points[16].y > rect.y && landmark.points[16].y < rect.y + rect.height
&&landmark.points[20].x > rect.x && landmark.points[20].x < rect.x + rect.width
&& landmark.points[20].y > rect.y && landmark.points[20].y < rect.y + rect.height
&& (abs(landmark.points[7].y - landmark.points[17].y) > (rect.height / 6.0)))
{
int rect_w = rect.width;
int rect_h = rect.height;
rect.width = rect_w * ZOOM_;
rect.height = rect_h * ZOOM_;
rect.x = max(rect.x - (ZOOM_ - 1.0) * rect_w / 2.0, 0.0);
rect.y = max(rect.y - (ZOOM_ - 1.0) * rect_h / 2.0, 0.0);
if (rect.x + rect.width > widths)
{
rect.width = widths - rect.x;
}
if (rect.y + rect.height > heights)
{
rect.height = heights - rect.y;
}
return true;
}
}
}
return false;
}
void getoffsetRect(Rect & rect, vector & all_rect, int cols, int rows, int max_offset)
{
srand((unsigned)time(NULL));
Rect rect0(rect), rect1(rect);
int offsetx = rand() % max_offset + 1;
int offsety = rand() % max_offset + 1;
if (rect.x > offsetx && rect.y > offsety)
{
rect0.x = rect.x - offsetx;
rect0.y = rect.y - offsety;
}
offsetx = rand() % max_offset + 1;
offsety = rand() % max_offset + 1;
if (rect.x + rect.width + offsetx < cols && rect.y + rect.height + offsety < rows)
{
rect1.x = rect.x + offsetx;
rect1.y = rect.y + offsety;
}
all_rect.push_back(rect0);
all_rect.push_back(rect1);
}
#define NEED_LANDMARK 5
#define CURRENT_LANDMARK 21
const int five_points[5] = { 7, 10, 14, 17, 19 };
string search_base = "H:\\UMD\\";
string search_dir_[] = { search_base + "umdfaces_batch1", search_base + "umdfaces_batch2", search_base + "umdfaces_batch3" };
string text_file[] = { search_base + "umdfaces_batch1\\umdfaces_batch1_ultraface.csv", search_base + "umdfaces_batch2\\umdfaces_batch2_ultraface.csv", search_base + "umdfaces_batch3\\umdfaces_batch3_ultraface.csv" };
string text_pre[] = { "batch1_aug_", "batch2_aug_", "batch3_aug_" };
string tail_[] = { ".jpg", ".jpg" , ".jpg" };
string base = search_base + "landmark_5\\augment_img\\";
string result_img = base + "result_img_" + to_string(SIZE) + "\\";
string result_txt = base + "landmark_" + to_string(SIZE) + "_5.txt";
const int theta_offset = 5;
const int theta_max = 20;
vector rotation_point;
int countNum = 0;
bool ready = false;
std::mutex mtx_syn;
std::condition_variable cv_syn;
void roll_yaw_pitch_data(LandMark result_mark, int temp, cunpd &pd, int model_id, DataPrepareUtil &dpu)
{
float roll = result_mark.direct[2];
string img_path = search_dir_[temp] + "\\" + result_mark.fileName;
if (_access(img_path.c_str(), 0) == -1)
{
cout << "coun't found filename" << img_path << endl;
return;
}
Mat img = imread(img_path);
Mat dstImg; //dstImg.create(heights, widths, CV_8UC1);
cvtColor(img, dstImg, CV_BGR2GRAY);
//yaw 增强 pitch 增强
for (int j = 0; j < 2; j++)
{
if (result_mark.direct[j] > -theta_offset && result_mark.direct[j] < theta_offset)
{
Rect rect;
LandMark landmark(result_mark);
bool success = getFaceRect(pd, model_id, dstImg, landmark, rect);
if (success)
{
vector all_rect;
getoffsetRect(rect, all_rect, img.cols, img.rows, 4);
for (int i = 0; i < 2; i++)
{
LandMark dst_landmark;
//vector filenames;
//splitString(landmark.fileName, filenames, "/");
//string filename = filenames[filenames.size()-1];
std::unique_lock lck(mtx_syn);
dst_landmark.fileName = text_pre[temp] + to_string(countNum++) + ".png";
lck.unlock();
//cout << img.rows << " " << rotat_img.cols << " " << rect.x << " " << rect.y << " " << rect.width << " " << rect.height << endl;
Mat roi_face = img(all_rect[i]);
cv::resize(roi_face, roi_face, Size(SIZE, SIZE));
//坐标转换
for (int k = 0; k < 5; k++)
{
dst_landmark.visible[k] = landmark.visible[five_points[k]];
dst_landmark.points[k].x = ((float)SIZE / all_rect[i].width) * (landmark.points[five_points[k]].x - all_rect[i].x);
dst_landmark.points[k].y = ((float)SIZE / all_rect[i].height) * (landmark.points[five_points[k]].y - all_rect[i].y);
}
imwrite(result_img + dst_landmark.fileName, roi_face);
std::unique_lock lck1(mtx_syn);
rotation_point.push_back(dst_landmark);
lck1.unlock();
}
}
}
}
// roll 增强
if (roll > -theta_offset && roll < theta_offset)
{
for (int i = -1; i < 2; i = i + 2)
{
Mat rotat_img;
LandMark landmark(result_mark);
int theta = (rand() % theta_max + theta_offset) * i;
rotation(theta, img, rotat_img, Size(SIZE, SIZE), landmark, CURRENT_LANDMARK);
Mat dstImg; //dstImg.create(heights, widths, CV_8UC1);
cvtColor(rotat_img, dstImg, CV_BGR2GRAY);
//for (int j = 0; j < CURRENT_LANDMARK; j++)
//{
// circle(rotat_img, Point(landmark.points[j]), 2, Scalar(255, 0, 0));
//}
//imshow("img", rotat_img);
//waitKey(0);
LandMark dst_landmark;
//vector filenames;
//splitString(landmark.fileName, filenames, "/");
//string filename = filenames[filenames.size()-1];
std::unique_lock lck(mtx_syn);
dst_landmark.fileName = text_pre[temp] + to_string(countNum++) + ".png";
lck.unlock();
Rect rect;
bool success = getFaceRect(pd, model_id, dstImg, landmark, rect);
if (success)
{
//cout << rotat_img.rows << " " << rotat_img.cols << " " << rect.x << " " << rect.y << " " << rect.width << " " << rect.height << endl;
Mat roi_face = rotat_img(rect);
cv::resize(roi_face, roi_face, Size(SIZE, SIZE));
//坐标转换
for (int k = 0; k < 5; k++)
{
dst_landmark.visible[k] = landmark.visible[five_points[k]];
dst_landmark.points[k].x = ((float)SIZE / rect.width) * (landmark.points[five_points[k]].x - rect.x);
dst_landmark.points[k].y = ((float)SIZE / rect.height) * (landmark.points[five_points[k]].y - rect.y);
}
imwrite(result_img + dst_landmark.fileName, roi_face);
std::unique_lock lck(mtx_syn);
rotation_point.push_back(dst_landmark);
if (rotation_point.size() > 500)
{
dpu.writePointVisibletoFile(result_txt, rotation_point, NEED_LANDMARK);
rotation_point.clear();
}
if (countNum % 500 == 0)
{
cout << "prepare data:" << countNum << endl;
}
lck.unlock();
}
}
}
}
vector result_point; //注意 使用多线程 时共同处理的 变量用 全局变量。
void deal_thread(int temp, int model_id, DataPrepareUtil &dpu, cunpd &pd)
{
while (true)
{
std::unique_lock lck(mtx_syn);
while (!ready) {
cv_syn.wait(lck);
}
//
auto itor = result_point.begin();
auto itor2 = result_point.end();
if (itor == itor2)
{
break;
}
LandMark landmark(result_point[0]);
result_point.erase(itor);
// cout << "landmark.fileName is:"< lck(mtx_syn);
ready = true;
cv_syn.notify_all();
}
int main()
{
cunpd pd;
int model_id = pd.AddNpdModel(0);
/*string img_path = "D:\\UMD\\result_img_96\\";
string result_path = "D:\\UMD\\arguement_data\\";
string img_text = img_path + "shutter_96_5_train.txt";
string result_text = result_path + "augment_96_5_train.txt";
augment_data(img_path, img_text, result_path, result_text);*/
string base_dir = base;
if (_access(base_dir.c_str(), 0) == -1)
{
_mkdir(base_dir.c_str());
}
string dir = result_img;
if (_access(dir.c_str(), 0) == -1)
{
_mkdir(dir.c_str());
}
srand((unsigned)time(NULL));
DataPrepareUtil dpUtil;
dpUtil.clearFileData(result_txt);
long count = 0;
vector rotation_point;
for (int temp = 0; temp < 3; temp++)
{
long countNum = 0;
//vector result_point;
dpUtil.readFileData(text_file[temp], result_point, CURRENT_LANDMARK);
std::thread threads[4];
for (int i = 0; i < 4; i++)
{
threads[i] = std::thread(deal_thread, temp, model_id, dpUtil, pd);
//threads[i] = std::thread(threadA, i, result_point, temp, model_id, dpUtil, pd);
}
cout << "temp start:" << temp << endl;
go();
for (auto &th : threads) {
th.join();
}
cout << "temp end:" << temp << endl;
}
if (rotation_point.size() > 0)
{
dpUtil.writePointVisibletoFile(result_txt, rotation_point, NEED_LANDMARK);
rotation_point.clear();
}
system("PAUSE");
return 0;
}
void test_thread() {
//1.
std::thread t(foo, "hello");
t.join();
//2.
std::packaged_task task([](int a) {std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "my task" << std::endl; return a; });
std::future result = task.get_future();
std::thread(std::move(task), 2).detach();
std::cout << "Waiting...." << std::endl;
//result.wait();
//result.get会阻塞,直到对应线程完成
std::cout << "Done result is:" << result.get() << std::endl;
//3.
std::packaged_task task1(foo);
std::future result1 = task1.get_future();
string str = "liu";
std::thread(std::move(task1), str).detach();
//result1.get会阻塞,直到对应线程完成
std::cout << "task1:" << result1.get() << std::endl;
}