C++:thread多线程及编程实现

概念:

多线程是实现并发或并行的一种手段,并行是指两个或多个独立的操作同时进行并发是在一个时间段内执行多个操作。

在单核时代,多个线程是并发的,在一个时间段内轮流执行;而在多核时代,多个线程可以实现真正的并行,在多核上真正独立的并行执行。例如现在常见的4核4线程可以并行4个线程;4核8线程则使用了超线程技术,把一个物理核模拟为2个逻辑核心,可以并行8个线程。

 

线程调用:

每个进程至少有一个线程,执行main()函数的线程, 其余线程有其各自的入口函数(线程函数)。

启用线程有以下规则:
(1)当线程执行完线程函数后, 线程也会退出

(2)如果不传入线程函数, 线程不会运行.

(3)线程函数不能重载, 否则不能编译.

(4)在为一个线程创建了一个 thread 对象后, 如果线程已启动, 必须要明确是加入线程(join)还是分离线程(detach).

(5)如果 thread 对象销毁之前还没有调用 join 或 detach, 程序就会发生异常而终止,这是因为thread 的析构函数会调用 terminate()。因此, 在销毁之前必须确保线程调用了join或detach,即便是有异常发生时。
(6)join()是简单粗暴的等待线程完成, 即阻塞主线程(main). [注]:如果在线程启动后到主线程在调用 join() 前的代码中发生了异常, 此时将会导致主线程永远没有机会执行.

  (7) detach()将子线程从主线程中分离,独立运行,不会阻塞主线程;

  (8) 其他函数,

        thread::hardware_concurrency() - 返回 CPU 核心线程数. 如果无法查询系统信息时, 返回0. 
        get_id() - 返回 thread 对象关联的线程的 id. 如果所有权已转移, 或线程函数已返回, 返回0.
        this_thread::get_id() 取得当前线程的 id.

编程实例:

1. join()

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void thread01()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 01 is working !" << endl;
		Sleep(100);
	}
}
void thread02()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 02 is working !" << endl;
		Sleep(200);
	}
}

int main()
{
	///1. join阻塞主线程
	thread task01(thread01);
	thread task02(thread02);
	task01.join();
	task02.join();

	for (int i = 0; i < 5; i++)
	{
		cout << "Main thread is working !" << endl;
		Sleep(200);
	}
	system("pause");
	return 0;
}

 

2. detach主线程和两个子线程并行执行

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

void thread01()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 01 is working !" << endl;
		Sleep(100);
	}
}
void thread02()
{
	for (int i = 0; i < 5; i++)
	{
		cout << "Thread 02 is working !" << endl;
		Sleep(200);
	}
}

int main()
{
	///detach不阻塞主线程
	thread task01(thread01);
	thread task02(thread02);
	task01.detach();
	task02.detach();

	for (int i = 0; i < 5; i++)
	{
		cout << "Main thread is working !" << endl;
		Sleep(200);
	}
	system("pause");
	return 0;
}

3. 带参数子线程

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

//定义带参数子线程
void thread01(int num)
{
	for (int i = 0; i < num; i++)
	{
		cout << "Thread 01 is working !" << endl;
		Sleep(100);
	}
}
void thread02(int num)
{
	for (int i = 0; i < num; i++)
	{
		cout << "Thread 02 is working !" << endl;
		Sleep(200);
	}
}

int main()
{
	thread task01(thread01, 5);  //带参数子线程
	thread task02(thread02, 5);
	task01.detach();
	task02.detach();

	for (int i = 0; i < 5; i++)
	{
		cout << "Main thread is working !" << endl;
		Sleep(200);
	}
	system("pause");
}

4. 多线程数据竞争

多个线程同时对同一变量进行操作的时候,如果不对变量做一些保护处理,有可能导致处理结果异常

#include <iostream>
#include <thread>
#include <Windows.h>

using namespace std;

int totalNum = 100;

void thread01()
{
	while (totalNum > 0)
	{
		cout << totalNum << endl;
		totalNum--;
		Sleep(100);
	}
}
void thread02()
{
	while (totalNum > 0)
	{
		cout << totalNum << endl;
		totalNum--;
		Sleep(100);
	}
}

int main()
{
	thread task01(thread01);
	thread task02(thread02);
	task01.detach();
	task02.detach();
	system("pause");
}

 

 

异常:一是有很多变量被重复输出了,而有的变量没有被输出;二是正常情况下每个线程输出的数据后应该紧跟一个换行符,但这里大部分却是另一个线程的输出。

这是由于第一个线程对变量操作的过程中,第二个线程也对同一个变量进行各操作,导致第一个线程处理完后的输出有可能是线程二操作的结果。

针对这种数据竞争的情况,可以使用线程互斥对象mutex保持数据同步。

mutex类的使用需要包含头文件mutex。
 

#include <iostream>
#include <thread>
#include <Windows.h>
#include <mutex>

using namespace std;

mutex mu;  //线程互斥对象

int totalNum = 100;

void thread01()
{
	while (totalNum > 0)
	{
		mu.lock(); //同步数据锁
		cout << totalNum << endl;
		totalNum--;
		Sleep(100);
		mu.unlock();  //解除锁定
	}
}
void thread02()
{
	while (totalNum > 0)
	{
		mu.lock();
		cout << totalNum << endl;
		totalNum--;
		Sleep(100);
		mu.unlock();
	}
}

int main()
{
	thread task01(thread01);
	thread task02(thread02);
	task01.detach();
	task02.detach();
	system("pause");
}

加入互斥后正常输出。

5. 常见示例:

#include <thread>
#include <iostream>

using namespace std;

int parallel_fun(int idx)
{
	cout << idx << endl;
	return 0;
}


int main()
{
	
	int flages[4];
	thread th1([&]() {flages[0] = parallel_fun(1); });
	thread th2([&]() {flages[1] = parallel_fun(2); });
	thread th3([&]() {flages[2] = parallel_fun(3); });
	thread th4([&]() {flages[3] = parallel_fun(4); });
	th1.join();
	th2.join();
	th3.join();
	th4.join();

	return 0;
}

结果:

 

参考文献:

1. https://www.cnblogs.com/wangguchangqing/p/6134635.html

2. https://www.cnblogs.com/diysoul/p/5934622.html

3. https://blog.csdn.net/dcrmg/article/details/53912941

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值