并发编程

文章目录
  1. 基本概念
  2. 并发与并行
  3. 原子性
  4. 线程安全
  5. C++

在学习操作系统的进程和线程部分理解进程和线程的概念, 进程和线程具有并发性, 希望可以在代码层面学习并实践一下

基本概念

采用多线程的目的其实就是尽可能的利用CPU资源去处理我们的业务, 还有一个就是在模拟现实场景的时候对每一角色进行线程的分配, 比如观察者模式

并发与并行

  • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
  • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

  • 并发是一个处理器同时处理多个任务,而并行多个处理器或者是多核的处理器同时处理多个不同的任务
  • 并发是逻辑上的同时发生(simultaneous),而并行是物理上的同时发生

原子性

A想要从自己的帐户中转1000块钱到B的帐户里。那个从A开始转帐,到转帐结束的这一个过程,称之为一个事务。在这个事务里,要做如下操作:

  1. 从A的帐户中减去1000块钱。如果A的帐户原来有3000块钱,现在就变成2000块钱了。

  2. 在B的帐户里加1000块钱。如果B的帐户如果原来有2000块钱,现在则变成3000块钱了。

如果在A的帐户已经减去了1000块钱的时候,忽然发生了意外,比如停电什么的,导致转帐事务意外终止了,而此时B的帐户里还没有增加1000块钱。那么,我们称这个操作失败了,要进行回滚。回滚就是回到事务开始之前的状态,也就是回到A的帐户还没减1000块的状态,B的帐户的原来的状态。此时A的帐户仍然有3000块,B的帐户仍然有2000块。

我们把这种要么一起成功(A帐户成功减少1000,同时B帐户成功增加1000),要么一起失败(A帐户回到原来状态,B帐户也回到原来状态)的操作叫原子性操作, 也就是在操作过程中不能被打断, 如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行, 这种特性就叫原子性

线程安全

线程安全是指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。我们通常说一段代码是线程安全的, 反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

1
2
3
4
void transferMoney(User from, User to, float amount){
to.setMoney(to.getBalance() + amount);
from.setMoney(from.getBalance() - amount);
}

C++

  1. 下载 x86_64-w64-mingw32-gcc-4.8-stdthread-win64_rubenvb.7z编译器并在Codeblocks中配置

  2. 具体配置见 stackoverflow : C++11, GCC 4.8.1,Code::Blocks, threading, what a head ache

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <stdlib.h>

#include <chrono> // std::chrono::seconds
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for

void thread_task(int n) {
std::this_thread::sleep_for(std::chrono::seconds(n));
std::cout << "hello thread "
<< std::this_thread::get_id()
<< " paused " << n << " seconds" << std::endl;
}

int main(int argc, const char *argv[])
{
std::thread threads[5];
std::cout << "Spawning 5 threads...\n";
for (int i = 0; i < 5; i++) {
threads[i] = std::thread(thread_task, i + 1);
}
std::cout << "Done spawning threads! Now wait for them to join\n";
for (auto& t: threads) {
t.join();
}
std::cout << "All threads joined.\n";

return EXIT_SUCCESS;
}

Java中的多线程你只要看这一篇就够了
Cplusplus-Concurrency-In-Practice