Skip to content

C++ 进阶

标准库

  • vector
    • 尾端可长
    • vector<T> arr = {};
    • vector<T> arr(n[,val])
    • .assign(b,e)(n,v)
    • .begin() .end() 首/末位迭代器 类似指针
    • .size() .resize() 几个位置
    • .capacity() ,reserve() 多少空间
    • .back() .front() 第一个 最后一个
    • .push_back(val) .pop_back() 删除/放到最后
    • .empty() 是否为[]
    • .erase(b,e) 删除 arr2.erase(arr2.begin()); 可以删除首元素
    • .insert(p,n,val) 插入 .emplace(iter,v) 插入一个时可用
    • arr1.swap(arr2) 交换
    • at()
    • sort() 排序 <algorithm>
    • unique() 去重
    • reverse() 反转
    • max/min_element(b,e) 最大小值
    • 遍历
      • for(auto i : arr){}
      • for(int i=0;i<arr.size();i++)
      • i = a.begin();while(i!=a.end())i++
    • 截取
      • vector<int> arr2(arr1.begin() + 1, arr1.end() - 1);
      • arr2.assign(arr1.begin() + 1, arr1.end() - 1);
    • 合并 arr1.insert(arr1.end(),arr2.begin(),arr2.end());
  • string
    • 字符串
    • string s = "hello" char*转string
    • string s = to_string(num) int转string
    • string s(n,ch)
    • string s2(s1,b,e)
    • s+='c' s.append('c')
    • s[2] s.at(2)
    • .size() .length
    • .find(sub)
    • .empty() .clear() .insert() .erase(p,n)
    • .substr(p,n) 子串
    • .compare("hello") 比较
    • .c_str() 转char*
  • map unordered_map
    • map<T,T> m = { {k1,v1\},{k2,v2} }
    • .insert(pair<int, string>(k, v))
    • m[k] = v
    • .find(k) 没找到返回m.end()
    • .earse(k) .earse(b,e)
    • .size()
    • .key_comp() value_comp()
    • 遍历
      • for(auto &&i : m)
      • .first() .second()
  • deque
    • 双端队列
    • deque<T> q
    • 大部分api与vector类似
    • .push_front(v) .pop_front() .push_back(v) .pop_back()
    • emplace_front(k) .emplace_back(v) 在前后插入
  • list
  • stack
  • queue
  • set
cpp
void SplitString(const std::string& s, std::vector<std::string>& v, const std::string& c)
{
  std::string::size_type pos1, pos2;
  pos2 = s.find(c);
  pos1 = 0;
  while(std::string::npos != pos2)
  {
    v.push_back(s.substr(pos1, pos2-pos1));
 
    pos1 = pos2 + c.size();
    pos2 = s.find(c, pos1);
  }
  if(pos1 != s.length())
    v.push_back(s.substr(pos1));
}

多进程

  • <unistd.h>
  • pid_t pid = fork();
  • if(pid==-1){fail}
  • if(pid==0){son process} exit(0);
  • else{father process} pid_t wait(int *status)

多线程

并行计算框架

  • pthread.h 是c++98的用法,仅支持linux, c++11改用thread
  • 创建
    • <thread>
    • thread task(taskFunc,arg); 开启线程运行
    • task.join() 运行完才往下走
    • task.detach() 后台运行和主进程一块结束 (守护进程)
  • this_threadd
    • get_id() 获取id
    • yield() 放弃
    • sleep_for(time) 暂停
    • sleep_until() 等会儿执行
  • 互斥量
    • mutex 基本
    • recursive_mutex 递归
    • time_mutex 定时
    • recursive_timed_mutex 定时递归
  • lock 锁
    • lock()
    • unlock()
    • trylock() 未上锁则锁住 已上锁返回true 同一个线程死锁
    • lock_guard 对象
    • unique_lock
  • 原子操作 解决互斥锁速度慢的问题
    • #include <atomic>
    • atomic_int total(0);
    • total += 1; 正常使用
  • condition_variable 条件变量
    • condition_variable对象
    • wait() 阻塞等通知
    • wait_for() 等通知和超时
    • wait_until() 等通知和时间点
    • notify_one() 解锁一个
    • notify_all() 通知解锁所有
    • cv_status() 表示状态
  • 线程池
    • 在程序开始时创建多个线程,后面拿来用就行了,用完放回
  • 信号量
    • <semaphore>
    • counting_semaphore sem(0); 初始值
    • sem.acquire(); 等待
    • sem.release(); 给出
  • 死锁
    • 任务一拿着锁1等锁2
    • 任务二拿着锁2等锁1
cpp
#include <iostream>
#include <thread>
using namespace std;

void thread_1()
{
  while (1)
  {
    cout << "子线程1111" << endl;
    // this_thread::sleep_for(chrono::seconds(1));
  }
}

void thread_2(int x)
{
  while (1)
  {
    cout << "子线程2222" << endl;
    // this_thread::sleep_for(chrono::seconds(2));
  }
}

int main()
{
  thread first(thread_1);
  thread second(thread_2, 100);

  first.detach();
  second.detach();
  first.join();
  second.join();
  for (int i = 0; i < 10; i++)
    cout << "主线程\n";

  return 0;
}
cpp
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int a = 0;

mutex mtx;
void print_block(int n, int c)
{
  // mtx.lock();
  // lock_guard<mutex> guard(mtx);
  unique_lock<mutex> unique(mtx);
  for (int i = 0; i < n; ++i)
  {
    a += c;
    cout << a << ' ';
  }
  cout << '\n';
  // mtx.unlock();
}
int main()
{
  thread th1(print_block, 50, 1);
  thread th2(print_block, 50, -1);

  th1.join();
  th2.join();
  return 0;
}
cpp
#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

deque<int> q;
mutex mt;
condition_variable cond;

void thread_producer()
{
  int count = 10;
  while (count > 0)
  {
    unique_lock<mutex> unique(mt);
    q.push_front(count);
    unique.unlock();
    cout << "producer a value: " << count << endl;
    cond.notify_one();
    this_thread::sleep_for(chrono::seconds(1));
    count--;
  }
}

void thread_consumer()
{
  int data = 0;
  while (data != 1)
  {
    unique_lock<mutex> unique(mt);
    while (q.empty())
      cond.wait(unique);
    data = q.back();
    q.pop_back();
    cout << "consumer a value: " << data << endl;
    unique.unlock();
  }
}

int main()
{
  thread t1(thread_consumer);
  thread t2(thread_producer);
  t1.join();
  t2.join();
  return 0;
}
cpp
#include <vector>
#include <queue>
#include <thread>
#include <iostream>
#include <condition_variable>
using namespace std;

const int MAX_THREADS = 1000; // 最大线程数目

template <typename T>
class threadPool
{
public:
  threadPool(int number = 1);
  ~threadPool();
  bool append(T *task);
  // 工作线程需要运行的函数,不断的从任务队列中取出并执行
  static void *worker(void *arg);
  void run();

private:
  // 工作线程
  vector<thread> workThread;
  // 任务队列
  queue<T *> taskQueue;
  mutex mt;
  condition_variable condition;
  bool stop;
};

template <typename T>
threadPool<T>::threadPool(int number) : stop(false)
{
  if (number <= 0 || number > MAX_THREADS)
    throw exception();
  for (int i = 0; i < number; i++)
  {
    cout << "create thread:" << i << endl;
    workThread.emplace_back(worker, this);
  }
}

template <typename T>
inline threadPool<T>::~threadPool()
{
  {
    unique_lock<mutex> unique(mt);
    stop = true;
  }
  condition.notify_all();
  for (auto &wt : workThread)
    wt.join();
}

template <typename T>
bool threadPool<T>::append(T *task)
{
  // 往任务队列添加任务的时候,要加锁,因为这是线程池,肯定有很多线程
  unique_lock<mutex> unique(mt);
  taskQueue.push(task);
  unique.unlock();
  // 任务添加完之后,通知阻塞线程过来消费任务,有点像生产消费者模型
  condition.notify_one();
  return true;
}
template <typename T>
void *threadPool<T>::worker(void *arg)
{
  threadPool *pool = (threadPool *)arg;
  pool->run();
  return pool;
}

template <typename T>
void threadPool<T>::run()
{
  while (!stop)
  {
    unique_lock<mutex> unique(this->mt);
    // 如果任务队列为空,就停下来等待唤醒,等待另一个线程发来的唤醒请求
    while (this->taskQueue.empty())
      this->condition.wait(unique);
    T *task = this->taskQueue.front();
    this->taskQueue.pop();
    if (task)
      task->process();
  }
}

class Task
{
private:
  int total = 0;

public:
  void process();
};

// 任务具体实现什么功能,由这个函数实现
void Task::process()
{
  // 这里就输出一个字符串
  cout << "task successful " << endl;
  this_thread::sleep_for(chrono::seconds(1));
}

int main(void)
{
  threadPool<Task> pool(1);

  while (1)
  {
    Task *task = new Task();
    pool.append(task);
    delete task;
  }
}
cpp
#include <iostream>
#include <semaphore>
#include <thread>
using namespace std;

counting_semaphore sem(0);

void task1()  // 线程函数 1 打印 a
{
  sem.acquire();
  cout << "task1\n" << endl;
}
void task2()  // 线程函数 2 打印 l
{
  cout << "task2\n" << endl;
  this_thread::sleep_for(chrono::seconds(2));
  sem.release();
}

int main() {
  thread s1(task1);
  thread s2(task2);

  s1.join();
  s2.join();
  return 0;
}
cpp
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

mutex mt1;
mutex mt2;
void thread1() {
  cout << "thread1 begin" << endl;
  lock_guard<mutex> guard1(mt1);
  this_thread::sleep_for(chrono::seconds(1));
  lock_guard<mutex> guard2(mt2);
  cout << "hello thread1" << endl;
}
void thread2() {
  cout << "thread2 begin" << endl;
  lock_guard<mutex> guard1(mt2);
  this_thread::sleep_for(chrono::seconds(1));
  lock_guard<mutex> guard2(mt1);
  cout << "hello thread2" << endl;
}

int main() {
  thread t1(thread1);
  thread t2(thread2);
  t1.join();
  t2.join();
  cout << "thread end" << endl;
  return 0;
}

Socket

  • server
    • socket()
    • bind()
    • listen()
    • accept()
    • read() recv()
    • write() send()
    • close()
  • client
    • socket()
    • connect()
    • read() recv()
    • write() send()
    • close()

聊天室

cpp
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <map>
#include <mutex>
#include <thread>
using namespace std;

int cnt = 0;
mutex mtx;
map<string, int> clients;

void sendMsg(string msg) {
  for (auto i : clients) send(i.second, msg.c_str(), msg.length(), 0);
}

void online(int client) {
  char msg[100] = {0};
  while (recv(client, msg, 100, 0) > 0) {
    cout << msg << endl;
    if (msg[0] == '@') {
      if (clients.find(msg) == clients.end()) {
        clients[msg] = client;
        sendMsg(msg);
      } else {
        cout << "already in" << endl;
        mtx.lock();
        cnt--;
        mtx.unlock();
        close(client);
        // return;
      }
    } else
      sendMsg(msg);
  }
  // 连接断开
  cout << "断开" << endl;
  mtx.lock();
  for (auto i : clients) {
    if (i.second == client) {
      cout << i.first << "leave" << endl;
      clients.erase(i.first);
      break;
    }
  }
  cnt--;
  mtx.unlock();
  close(client);
  return;
}

int main() {
  struct sockaddr_in serverAddr, clientAddr;
  unsigned int temp = sizeof(clientAddr);
  // pid
  int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  int client;

  serverAddr.sin_family = AF_INET;                 // ipv4
  serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);  // ip
  serverAddr.sin_port = htons(8080);               // 端口
  bind(server, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
  listen(server, 99);

  while (1) {
    client = accept(server, (struct sockaddr *)&clientAddr, &temp);

    mtx.lock();
    cnt++;
    mtx.unlock();

    thread th(online, client);
    th.detach();
    cout << "new connection" << endl;
  }
  close(server);
  return 0;
}
cpp
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <map>
#include <mutex>
#include <thread>
using namespace std;

string name;

void send_msg(int sock) {
  string msg;
  while (1) {
    cin >> msg;

    if (msg == "quit") {
      close(sock);
      exit(0);
    }
    
    string name_msg = name + ": " + msg;
    send(sock, name_msg.c_str(), name_msg.length() + 1, 0);
  }
}

void recv_msg(int sock) {
  while (1) {
    char name_msg[100] = {0};
    int str_len = recv(sock, name_msg, 100, 0);
    if (str_len < 1) {
      exit(-1);
    }
    cout << string(name_msg) << endl;
  }
}

int main() {
  cout << "name:";
  cin >> name;

  struct sockaddr_in serverAddr;
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  serverAddr.sin_port = htons(8080);

  int pid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  connect(pid, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
  string temp = "@" + name;
  send(pid, temp.c_str(), temp.length(), 0);

  std::thread snd(send_msg, pid);
  std::thread rcv(recv_msg, pid);
  snd.join();
  rcv.join();

  close(pid);
  return 0;
}