test(私人笔记)

这篇笔记涵盖了C/C++中的多线程同步与异步、路径处理、指针与迭代器的区别、C++中的string操作、内存管理、数据结构如排序算法和链表、面向对象特性、模板、STL以及智能指针的使用。此外,还涉及C语言中的指针、结构体、共用体、内存分配、C++中的IO流、异常处理等内容。笔记中强调了多线程编程中的同步和异步概念,以及如何通过互斥锁保证线程安全。同时,介绍了C++11中的新特性,如智能指针和更方便的遍历语法。
摘要由CSDN通过智能技术生成

我想记录的

多线程和多进程

image-20230425145743954

pthread_t id        属性   回调函数指针       函数的入参(参数)
​
pthread_join(线程id,返回值)       等待线程结束
​
3.pthread_mutex_init:初始化互斥锁
函数原型:int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
该函数用于初始化一个互斥锁,使得该锁可以用于多线程之间的同步。
​
4.pthread_mutex_lock:加锁
函数原型:int pthread_mutex_lock(pthread_mutex_t *mutex);
该函数用于加锁,即获取互斥锁。如果该锁已经被另一个线程获取,则该函数会阻塞当前线程,直到该锁可用为止。
​
5.pthread_mutex_unlock:解锁
函数原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
该函数用于解锁,即释放互斥锁。如果该锁未被获取,则该函数会导致未定义的行为。
​
6.pthread_cond_init:初始化条件变量
函数原型:int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
该函数用于初始化一个条件变量,使得该变量可以用于多线程之间的同步。
​
7.pthread_cond_wait:等待条件变量
函数原型:int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
该函数用于等待条件变量的发生。在等待之前,必须已经获取了指定的互斥锁。
​
8.pthread_cond_signal:发送信号
函数原型:int pthread_cond_signal(pthread_cond_t *cond);

同步

#include <stdio.h>
#include <pthread.h>
​
pthread_mutex_t bed_mutex, desk_mutex; // 定义互斥锁
​
void *student_A(void *ptr) {
  printf("A wants to sleep. \n");
  pthread_mutex_lock(&bed_mutex);  // A先锁住床,B不能访问
  printf("A is sleeping. \n");
  pthread_mutex_lock(&desk_mutex); // A再锁住书桌,保证A独占资源
  printf("A is studying. \n");
  pthread_mutex_unlock(&desk_mutex);  // A完成对书桌的访问,解锁
  pthread_mutex_unlock(&bed_mutex);   // A完成对床的访问,解锁
}
​
void *student_B(void *ptr) {
  printf("B wants to study. \n");
  pthread_mutex_lock(&desk_mutex);  // B先锁住书桌,A不能访问
  printf("B is studying. \n");
  pthread_mutex_lock(&bed_mutex);   // B再锁住床,保证B独占资源
  printf("B is sleeping. \n");
  pthread_mutex_unlock(&bed_mutex);   // B完成对床的访问,解锁
  pthread_mutex_unlock(&desk_mutex);  // B完成对书桌的访问,解锁
}
​
int main() {
  pthread_t thread_A, thread_B;
  int ret1, ret2;
​
  pthread_mutex_init(&bed_mutex, NULL);   // 初始化床的互斥锁
  pthread_mutex_init(&desk_mutex, NULL);  // 初始化书桌的互斥锁
​
  ret1 = pthread_create(&thread_A, NULL, student_A, NULL);
  ret2 = pthread_create(&thread_B, NULL, student_B, NULL);
​
  if (ret1 || ret2)
  {
  printf("Error: pthread_create failed. \n");
  return 1;
  }
​
  pthread_join(thread_A, NULL);
  pthread_join(thread_B, NULL);
​
  pthread_mutex_destroy(&bed_mutex); // 销毁床的互斥锁
  pthread_mutex_destroy(&desk_mutex); // 销毁书桌的互斥锁
​
  return 0;
}

在上面的代码中,首先定义了两个互斥锁,分别表示床和书桌。在函数student_A中,A首先锁住床,然后锁住书桌,完成对资源的访问之后,先解锁书桌,再解锁床。在函数student_B中,B则先锁住书桌,然后锁住床,完成对资源的访问之后,先解锁床,再解锁书桌。这样,可以保证A和B之间的资源访问是同步的,即同一时刻只有一个人能访问资源。

在主函数中,使用pthread_create函数创建线程,分别代表A和B两个人,并使用pthread_mutex_init函数初始化互斥锁,使得多线程之间可以进行同步访问。使用pthread_join函数等待线程结束后再退出,最后使用pthread_mutex_destroy函数销毁互斥锁,释放相关资源。

异步

异步编程是一种不同于多线程编程的方式,它可以帮助程序在执行I/O等任务时更高效地利用CPU资源,提高程序的响应速度。在Linux系统中,可以使用一些库来实现异步编程,比如libevent、libuv和Boost.Asio等。

这些库在实现异步编程时,通常使用事件循环机制,也就是当某个事件发生时,立即触发相应的处理函数,而不是等待事件的完成,从而提高了程序的效率。在事件循环机制中,程序会不断地循环等待事件的发生,并在事件发生时立即执行相应的处理函数,而不是在事件发生后等待处理函数的完成。

下面是一个使用libevent库实现异步编程的示例代码,用于监听网络端口的连接请求。

#include <stdio.h>
#include <event.h>
​
void accept_callback(int fd, short events, void *arg) {
  printf("A new connection is coming. \n");
}
​
int main() {
  struct event_base *base;
  struct event *listener_event;
​
  base = event_base_new();  // 创建事件处理器
​
  // 创建监听事件
  listener_event = event_new(base, -1, EV_READ | EV_PERSIST, accept_callback, NULL);
  event_add(listener_event, NULL);  // 添加监听事件
​
  event_base_dispatch(base);  // 启动事件处理循环
​
  return 0;
}

在这个代码中,首先使用event_base_new函数创建一个事件处理器,用于管理事件循环的生命周期。然后,使用event_new函数创建一个事件监听器,并将其添加到事件处理器中。当事件循环启动后,程序会在accept_callback函数中等待连接请求的到来,并在连接请求到来时立即触发相应的处理函数。

需要注意的是,异步编程需要开发者对程序的执行流程有较为深刻的理解,并且需要避免出现阻塞等问题,否则会影响程序的响应速度。在实际开发中,需要根据具体的需求选择合适的库和机制来实现异步编程。

路径

在c++中,加载图片文件等等,一般复制路径后,要把\(反斜杠)改成/(正斜杠)或者两个反斜杠。如:0

Mat src = imread("C:/Users/27119/Pictures/untitled.png");
imshow("input", src);
waitKey(0);
destroyAllWindows();
return 0;

for(auto &a:b)、for(auto a:b)、for(const auto &a:b)

b为数组或容器,是被遍历的对象

for(auto &a:b),循环体中修改a,b中对应内容也会修改

for(auto a:b),循环体中修改a,b中内容不受影响

for(const auto &a:b),a不可修改,用于只读取b中内容

#include <iostream>
using namespace std;
void main()
{
    int arr[5] = {1,2,3,4,5};
    for (auto &a : arr)
    {
        cout << a;
    }
    cout << endl;
    for (auto a : arr)
    {
        cout << a;
    }
    cout << endl;
    system("pause");
}

如果仅仅对b进行读取操作,而不修改,两者效果一致,如下:

img

如果需要对b进行修改,则需要用for(auto &a:b),如下:

#include <iostream>
using namespace std;
void main()
{
    int arr[5] = {1,2,3,4,5};
    for (auto &a : arr)
    {
        a++;
    }
    for (auto a : arr)
    {
        cout << a;
    }
    cout << endl;
    system("pause");
}

img

如果不加&符号,则b不会发生任何修改。

strlen(c库函数)和sizeof、length、size的区别

可以理解是一个杯子里面有水,length size、strlen(不能用于string)就是水,size就是最多能装多少水。

char str[1024] = "fdsa";
cout << sizeof(str);   //显示的1024,sizeof遇到char数组的空内容也加上去
cout << strlen(str) << endl;//显示4,strlen不会遇空不增加

image-20221222134636914

析构函数的注意

假如有一个类,在类中已经声明了,但是一直没有初始化,就会出错。

new除外(因为是delect释放)

class stu
{
public:
    int id;
    stu(int id)
    {
        this->id = id;
    }
    ~stu();
​
};
int main()
{
    stu p(1);
}

模板栈

当我们做模板栈的时候,入栈和出栈后不会出现问题,但是返回栈顶指针(gettop())会出现问题

image-20220718183339105

原因是模板栈返回栈顶时,栈顶判断为空的,返回的数据不能为空,T类型也不知道返回什么,只能抛出异常。

image-20220718183352451

image-20220718183407887

智能指针

c++中有几种不同的智能指针:std::unique_ptr、std::shared_ptr以及std::weak_ptr

进行资源管理:不需要自动释放。防止内存泄漏

定义方式:

#include<memory>
std::unique_ptr<int> ptr=std::make_unique<int>(5);

以上的std::make_unique函数是C++14开始提供的,用于创建一个std::unique_ptr实例。std::make_unique同时负责创建新的int对象,并将其初始化为5。

/*如何遍历复杂数据结构:

a数组和b数组不一定地址连续,我希望a++越界后到b的首地址。

*pa(a的首地址) al(a的长度)

*pb(b的首地址)

做判断 指针的地址>(pa+al)(越界),直接赋值给*pb

*/

乱七八糟的指针题目

#include<stdio.h>
int main()
{
    char* c[] = { "ENTER","NEW","POINT","FIRST" };
    char** cp[] = { c + 3,c + 2,c + 1 };
    char*** cpp = cp;
    printf("%s\n", **++cpp);
    printf("%s\n", *-- * ++cpp + 3);
    printf("%s\n", *cpp[-2] + 3);
    printf("%s\n", cpp[-1][-1] + 1);
    return 0;
   }
//第一个输出
**++cpp
=**(cp+1)
=*(c+2)
=“point”

#include<stdio.h>
int main()
{
    char* c[] = { "ENTER","NEW","POINT","FIRST" };
    printf("%s\n",*c+3);      //输出ER
    printf("%s\n",*(c+3)+3);  //输出ST
    printf("%s\n",*(c+1)+1);  //输出EW
    return 0;
}

! > 算术运算符 > 关系运算符 > && > || > 赋值运算符

优先级 运算符 名称或含义 使用形式 结合方向 说明
1 [] 数组下标 数组名[常量表达式] 左到右 --
() 圆括号 (表达式)/函数名(形参表) --
. 成员选择(对象) 对象.成员名 --
-> 成员选择(指针) 对象指针->成员名 --
2 - 负号运算符 -表达式 右到左 单目运算符
~ 按位取反运算符 ~表达式
++ 自增运算符 ++变量名/变量名++
-- 自减运算符 --变量名/变量名--
* 取值运算符 *指针变量
& 取地址运算符 &变量名
! 逻辑非运算符 !表达式
(类型) 强制类型转换 (数据类型)表达式 --
sizeof 长度运算符 sizeof(表达式) --
3 / 表达式/表达式 左到右 双目运算符
* 表达式*表达式
% 余数(取模) 整型表达式%整型表达式
4 + 表达式+表达式 左到右 双目运算符
- 表达式-表达式
5 << 左移 变量<<表达式 左到右 双目运算符
>> 右移 变量>>表达式
6 > 大于 表达式>表达式 左到右 双目运算符
>= 大于等于 表达式>=表达式
< 小于 表达式<表达式
<= 小于等于 表达式<=表达式
7 == 等于 表达式==表达式 左到右 双目运算符
!= 不等于 表达式!= 表达式
8 & 按位与 表达式&表达式 左到右 双目运算符
9 ^ 按位异或 表达式^表达式 左到右 双目运算符
10 | 按位或 表达式|表达式 左到右 双目运算符
11 && 逻辑与 表达式&&表达式 左到右 双目运算符
12 || 逻辑或 表达式||表达式 左到右 双目运算符
13 ?: 条件运算符 表达式1?表达式2: 表达式3 右到左 三目运算符
14 = 赋值运算符 变量=表达式 右到左 --
/= 除后赋值 变量/=表达式 --
*= 乘后赋值 变量*=表达式 --
%= 取模后赋值 变量%&
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值