C++ 多线程学习总结

C++ 多线程

  • 头文件
#include <thread>

创建线程 thread

jion与detach方式的区别

  • jion方式:必须等待已经创建的子线程任务执行完毕,才会继续往下执行。
    示例:
void my_func1_task()
{
	cout << "I am my_func1_task" << endl;
	cout << "my_func1_task end" << endl;
}

void my_func2_task(int x)
{
	cout << "I am my_func2_task" << endl;
	while (x--)
	{
		cout << "x:" << x << ";";
		sleep(1);
	}
	cout << endl;
	cout << "my_func2_task end" << endl;
}

int main(int argc, char *argv[])
{
	cout << "this is main()" << endl;
	thread thread_1(my_func1_task);
	//等待线程1完成
	thread_1.join();
	
	thread thread_2(my_func2_task, 10);
	//等待线程2完成
	thread_2.join();
	cout << "thread end" << endl;

	cout << "main end" << endl;
	return 0;
}

测试结果:
在这里插入图片描述

  • detach方式:启动的子线程自主在后台运行,当前主线程代码继续往下执行,无需等待子线程结束。
    注:该种情况下,主线程一般会进入while(1)循环执行主线程逻辑,否则整个进程会结束。
    示例:
void my_func1_task()
{
	cout << "I am my_func1_task" << endl;
	cout << "my_func1_task end" << endl;
}

void my_func2_task(int x)
{
	cout << "I am my_func2_task" << endl;
	while (x--)
	{
		cout << "x:" << x << ";";
		sleep(1);
	}
	cout << endl;
	cout << "my_func2_task end" << endl;
}

int main(int argc, char *argv[])
{
	cout << "this is main()" << endl;
	thread thread_1(my_func1_task);
	thread_1.detach();
	
	thread thread_2(my_func2_task, 10);
	thread_2.detach();
	cout << "thread end" << endl;

	cout << "main end" << endl;
	return 0;
}

测试结果:
在这里插入图片描述

互斥锁 mutex

  • 头文件
#include <mutex>

lock和unlock

不上锁测试示例:

int g_count = 10;

void my_func1_task()
{
	while (g_count-- > 0)
	{
		cout << "===func1===";
		sleep(1);
	}
	cout << endl;
}

void my_func2_task()
{
	while (g_count-- > 0)
	{
		cout << "***func2***";
		sleep(1);
	}
	cout << endl;
}

int main(int argc, char *argv[])
{
	cout << "this is main()" << endl;
	thread thread_1(my_func1_task);
	thread thread_2(my_func2_task);
	
	thread_1.join();
	thread_2.join();
	return 0;
}

测试结果:
在这里插入图片描述
上锁测试示例:

int g_count = 10;
mutex g_countMtx;

void my_func1_task()
{
	g_countMtx.lock();
	while (g_count-- > 0)
	{
		cout << "===func1===";
		sleep(1);
	}
	cout << endl;
	g_countMtx.unlock();
}

void my_func2_task()
{
	g_countMtx.lock(); 
	while (g_count-- > 0)
	{
		cout << "***func2***";
		sleep(1);
	}
	cout << endl;
	g_countMtx.unlock();
}

int main(int argc, char *argv[])
{
	cout << "this is main()" << endl;
	thread thread_1(my_func1_task);
	thread thread_2(my_func2_task);
	
	thread_1.join();
	thread_2.join();
	return 0;
}

测试结果:
在这里插入图片描述

lock_guard

  • 作用:防止在lock后,忘记unlock。
  • 使用:在创建lock_guard对象时,将尝试获取提供给它的互斥锁的所有权。当控制流离开lock_guard对象的作用域时,lock_guard析构并释放互斥锁。
  • 特点:创建即加锁,作用域结束自动析构并解锁;不能中途解锁,必须等作用域结束才能解锁。
  • 使用技巧:可以根据需要通过使用{}增加临时作用域。
测试示例-不加锁
int g_count = 0;

void func_1_task()
{
    while (1) {
        cout << "-------------------------" << endl;
        cout << "--- set count: " << ++g_count << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
}

void func_2_task()
{
    while (1) {
        cout << "*************************" << endl;
        cout << "***111 get count: " << g_count << endl;
        this_thread::sleep_for(chrono::seconds(1));
        cout << "***222 get count: " << g_count << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
}

int main()
{
    thread th_1(func_1_task);
    th_1.detach();
    thread th_2(func_2_task);
    th_2.detach();

    while (1)
    {
        this_thread::sleep_for(chrono::seconds(10));
    }
    return 0;
}

测试结果
在这里插入图片描述

测试示例-加锁
int g_count = 0;
mutex g_countMtx;

void func_1_task()
{
    while (1) {
        {
            lock_guard<mutex> guard(g_countMtx);
            cout << "-------------------------" << endl;
            cout << "--- set count: " << ++g_count << endl;
        }
        this_thread::sleep_for(chrono::seconds(1));
    }
}

void func_2_task()
{
    while (1) {
        {
            lock_guard<mutex> guard(g_countMtx);
            cout << "*************************" << endl;
            cout << "***111 get count: " << g_count << endl;
            this_thread::sleep_for(chrono::seconds(1));
            cout << "***222 get count: " << g_count << endl;
        }
        this_thread::sleep_for(chrono::seconds(1));
    }
}

int main()
{
    thread th_1(func_1_task);
    th_1.detach();
    thread th_2(func_2_task);
    th_2.detach();

    while (1)
    {
        this_thread::sleep_for(chrono::seconds(10));
    }
    return 0;
}

测试结果
在这里插入图片描述

信号量 sem

C++下使用的信号量,实际上使用的也是C语言中的信号量,即使用<semaphore.h>库。

sem参数

  • 头文件
#include <semaphore.h>
  • 类型
    sem_t
  • 函数接口
int sem_init(sem_t *sem, int pshared, unsigned int value);  // 创建信号量
int sem_post(sem_t *sem);    // 信号量的值加 1
int sem_wait(sem_t *sem);    // 信号量的值减 1
int sem_destroy(sem_t *sem); // 信号量销毁

示例

sem_t sem;

void func_1_task()
{
    cout << "start wait sem..." << endl;
    sem_wait(&sem);
    cout << "end wait sem..." << endl;
}

void func_2_task()
{
    sleep(5);
    cout << "I will post sem" << endl;
    sem_post(&sem);
}

int main()
{
    sem_init(&sem, 0, 0);

    thread th_1(func_1_task);
    th_1.detach();

    thread th_2(func_2_task);
    th_2.detach();

	while (1)
    {
        sleep(10);
    }
    sem_destroy(&sem);
    return 0;
}

测试结果
在这里插入图片描述

原子变量atomic

  • 多线程编程中常用的同步机制,它能确保对共享变量的操作在执行时不被其它线程的操作干扰。
  • 保证操作是原子级别的,要么全部完成,要么全部未完成。
  • 原子类型:整形、指针、布尔值。语法:std::atomic< T >
  • 内存模型:通过指定memory orders实现线程安全
  • 多线程安全,效率比互斥量高

成员函数

is_lock_free()函数

  • 检查当前atomic对象是否支持无锁操作。

store()函数

  • 将给定的值存储到原子对象中。
  • 存储操作的内存顺序默认为:std::memory_order_seq_cst(顺序一致性)

load()函数

  • 获取原子变量的当前值。
  • 内存操作默认为:std::memory_order_seq_cst(顺序一致性)

exchange()函数

  • 替换并返回原来的值。

支持的基本操作总结

  • 加法:a += n 或 a.fetch_add(n)
  • 减法:a -= n 或 a.fetch_sub(n))
  • 自增:a++ 或 a.fetch_add(1)
  • 自减:a-- 或 a.fetch_sub(1)
  • 与:a &= b 或 a.fetch_add(b)
  • 或:a |= b 或 a.fetch_or(b)
  • 异或:a ^= b 或 a.fetch_xor(b)
  • 交换:a.exchange(b)

原子变量应用示例

多线程不加锁

static int g_total = 0;

void func_task()
{
    int i = 0;
    for (i = 1; i < 101; i++) {
        g_total += i;
        this_thread::sleep_for(chrono::milliseconds(100));
    }
}

int main()
{
    thread th_1(func_task);
    thread th_2(func_task);
    th_1.join();
    th_2.join();
    cout << "*** g_total: " << g_total << endl;

    return 0;
}

测试结果
在这里插入图片描述

多线程加锁

static int g_total = 0;
mutex mtx;

void func_task()
{
    int i = 0;
    for (i = 1; i < 101; i++) {
        {
            lock_guard<mutex> guard(mtx);
            g_total += i;
            this_thread::sleep_for(chrono::milliseconds(100));
        }
    }
}

int main()
{
    thread th_1(func_task);
    thread th_2(func_task);
    th_1.join();
    th_2.join();
    cout << "*** g_total: " << g_total << endl;
    
    return 0;
}

测试结果
在这里插入图片描述

多线程使用原子变量

//static int g_total = 0;
atomic<int> g_total(0);

void func_task()
{
    int i = 0;
    for (i = 1; i < 101; i++) {
         g_total += i;//或 total.fetch_add(i);
         this_thread::sleep_for(chrono::milliseconds(100));
    }
}

int main()
{
    thread th_1(func_task);
    thread th_2(func_task);
    th_1.join();
    th_2.join();
    cout << "*** g_total: " << g_total.load() << endl;

    return 0;
}

测试结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值