我想记录的
多线程和多进程
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进行读取操作,而不修改,两者效果一致,如下:
如果需要对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"); }
如果不加&符号,则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不会遇空不增加
析构函数的注意
假如有一个类,在类中已经声明了,但是一直没有初始化,就会出错。
new除外(因为是delect释放)
class stu { public: int id; stu(int id) { this->id = id; } ~stu(); }; int main() { stu p(1); }
模板栈
当我们做模板栈的时候,入栈和出栈后不会出现问题,但是返回栈顶指针(gettop())会出现问题
原因是模板栈返回栈顶时,栈顶判断为空的,返回的数据不能为空,T类型也不知道返回什么,只能抛出异常。
智能指针
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 | = | 赋值运算符 | 变量=表达式 | 右到左 | -- |
/= | 除后赋值 | 变量/=表达式 | -- | ||
*= | 乘后赋值 | 变量*=表达式 | -- | ||
%= | 取模后赋值 | 变量%& |