自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

_

  • 博客(872)
  • 资源 (2)
  • 收藏
  • 关注

原创 muduo源码阅读:linux timefd定时器

零轮询编程模型是一种高效处理I/O操作的方法,旨在避免传统轮询(polling)带来的CPU资源浪费。传统的轮询会周期性地检查I/O设备是否准备好进行数据传输,可能导致大量的CPU时间被消耗在无意义的检查上。相比之下,零轮询编程模型利用了操作系统提供的机制(select/poll/epoll等),允许程序在等待I/O事件时进入阻塞状态,即不占用CPU资源,直到有实际的I/O事件发生才会唤醒程序进行处理。这种模型通过减少或消除不必要的检查循环。

2025-02-25 22:56:11 1001

原创 muduo源码阅读:socket常见操作及一些补充

读方向:从TCP连接中接收数据的操作。进程从TCP连接中读取来自远端的数据。应用程序正在执行读操作,它是在接收对方发送过来的数据。写方向:通过TCP连接发送数据的操作。进程向TCP连接中写入数据以发送给远端的应用程序。执行写操作时,你是在向对方发送数据。

2025-02-23 17:31:22 566

原创 muduo源码阅读:InetAddress类

InetAddress类对IP地址进行包装,是sockaddr_in的包装类。

2025-02-23 15:00:03 934

原创 muduo源码阅读:poller的实现

跨线程拷贝是指在一个线程中创建一个对象的副本,并将其传递给另一个线程进行操作。这种方式容易引发数据竞争和其他并发问题(见nocopyable)对象生命周期绑定所属 EventLoop 线程中的对象是什么?对象指的是PollPoller及其相关的 Channel 对象,生命周期是与创建它们的 EventLoop 线程绑定的,这些对象只能在创建它们的那个 EventLoop 线程中被访问和操作。为什么要绑定 EventLoop 线程的生命周期?

2025-02-23 11:43:55 1238

原创 muduo源码阅读:epoll底层原理

两个线程同时操作一个socket。用户程序调用epoll_wait后,内核循环检测就绪队列是否有就绪事件,如果有就绪事件,将就绪事件返回给用户,否则继续往下执行,判断epoll是否超时,超时返回0,如果没有超时则将epoll线程挂起,epoll线程陷入休眠状态,同时插入一个epoll等待队列项。当socket接收到数据后,会通过socket等待队列回调函数去检测epoll等待队列项,并将epoll线程唤醒,epoll线程被唤醒成功后,epoll线程再次查询就绪队列,此时就能成功返回socket事件。

2025-02-23 11:22:26 661

原创 muduo源码阅读:poll底层实现

poll是一种I/O多路复用机制,可以同时监视多个文件描述符,当其中任意一个文件描述符就绪时,就会通知程序进行相应的读写操作(和select一样)。poll机制与select机制类似,但是poll没有最大文件描述符数量的限制,所以在文件描述符数量较大时,poll的效率会更高。如何实现的的呢?poll引入一个结构体叫pollfd结构体,每个。

2025-02-23 11:20:29 788

原创 muduo源码阅读:select底层原理

fd_set;select位图为1024比特位图,通过整型数组模拟而成。select位图每个比特对应一个文件描述符数值。select位图数组长度为16,每个数组元素为8字节,一个字节为8比特,位图大小=16 * 8 * 8 = 1024比特。//设置fd对应位图位置为0。//判断fd对应位图位置是否为1。//设置fd对应位图位置为1。//整个位图清零。select编程select函数是Linux系统中的一种I/O多路复用机制,它可以同时监视多个文件描述符。nfds:最大文件描述符+1。

2025-02-23 11:18:49 710

原创 西工大VLSI复习指南

(2)很多地方不会考的,所以听不懂也没关系(听不懂是正常的,我们都听不懂),只要把重要的几个地方看懂就行了(后面会说哪些地方可能比较重要)。(1)开卷考试能带一张A4纸,所以认真准备只要写满都不至于挂科,而且考的不会很刁钻(会把我整理的资料放后面)(3)原书有700多页,很多地方都没有讲,我删减之后只有300页左右,我会把资料放到我优快云资源里面。今年考了4个题目,第一题是给了反相器的棒图,说哪个是NMOS和PMOS(PPT原图)。(2)反相器的棒图,横截面会看,知道每个位置对应的是什么。

2025-01-28 00:21:48 254

原创 数据结构:log-structed结构&&MemTable&&SSTable

Log-Structured 结构,有时候也会被称作是 Append-only Sequence of Data,因为所有的写操作都会不停地添加进这个数据结构中,而不会更新原来已有的值,这也是 Log-Structured 结构的一大特性。比如说,Google 的三驾马车之一,Bigtable 文件系统的底层存储数据结构采用的就是Log-Structured结构, MongoDB 和 HBase 这类的 NoSQL 数据库,它们的底层存储数据结构其实也是 Log-Structured 结构。

2025-01-25 17:25:01 879

原创 进程通信(11)System V共享内存区

具体来说,它会更新 shmid_ds 结构中的 shm_perm.uid、shm_perm.gid 和 shm_perm.mode 成员,这些值来自于 buf 指向的结构体。创建或获取共享内存标识符:使用shmget系统调用,根据给定的关键字(key)、大小和标志创建一个新的共享内存段或获取一个已存在的共享内存段的标识符(ID)。将共享内存段附加到进程地址空间:使用shmat系统调用将由shmget返回的共享内存段ID所标识的共享内存段附加到调用进程的地址空间。它只是解除了该进程对共享内存段的访问。

2024-12-30 23:50:21 634

原创 进程通信(10):Posix 共享内存区

POSIX.1提供了两种主要的方法来实现这一目标:1. 内存映射文件描述符获取:通过open函数打开一个文件,并获得其文件描述符。映射过程:使用mmap函数将该文件映射到当前进程的地址空间。适用场景:不仅可以用于父子进程间的共享,还可以用于无亲缘关系的进程之间。只要所有需要访问该共享内存区的进程都能够打开同一个文件,它们就可以共享由该文件映射而来的内存区域。2. 共享内存区对象描述符获取:通过shm_open函数打开或创建一个Posix IPC名字(可能是文件系统中的路径名),并返回一个描述符。

2024-12-30 22:47:43 899

原创 进程通信(9):记录上锁

而本章讨论的是另一种类型的读写锁,它允许有亲缘关系或无亲缘关系的进程之间共享文件的读与写。这种类型的锁是基于文件描述符并通过函数fcntl实现的,其维护是在内核层面完成的,并且是以进程ID来标识锁的所有者。内核不会阻止一个进程写入已被另一个进程读锁定的文件,也不会阻止一个进程读取已被另一个进程写锁定的文件。在这种情况下,所有涉及的进程都遵循约定,尊重其他进程设置的锁。例如,在网络编程中,守护程序通常都是协作的,它们访问共享资源如序列号文件,并且都在系统管理员的控制之下。解锁时,unlink掉锁文件。

2024-12-30 21:21:59 745

原创 进程通信(8)读写锁

读写锁是一种同步原语,用于管理对共享资源或临界区的访问,允许多个线程同时读取数据(共享锁),但当有线程需要写入数据时(独占锁),则要求排他性的访问,即不允许其他任何线程(无论是读还是写)同时访问该数据。这种机制在读操作远多于写操作的应用场景中,能显著提高并发性能。读写锁的工作原理(1)共享锁(读锁):当没有线程持有写锁时,任意数量的线程可以同时持有读锁。持有读锁的线程只能进行读操作,不能修改共享资源。

2024-12-30 20:34:45 1225

原创 C++并发编程实战:第4章 同步并发操作

std::future和std::shared_future通常与std::async、std::promise等一起使用来创建异步任务和管理其结果。如果 std::promise 或 std::packaged_task 在没有调用 set_value() 或 set_exception() 的情况下被销毁,那么与之关联的 std::future 会接收到一个 std::future_error 异常,错误码为std::future_errc::broken_promise。最优的选择是利用条件变量。

2024-12-27 17:46:12 1049

原创 C++并发编程实战 第三章 线程间共享数据

add_to_list() 和 list_contains() 函数使用 std::lock_guard 来确保对 some_list 的访问是互斥的,即一个线程在修改列表时,其他线程不能读取或修改该列表。除了上述特性外,std::unique_lock 还支持锁所有权的转移,这意味着你可以将一个 std::unique_lock 持有的锁转移给另一个 std::unique_lock 实例。因为两个线程可能尝试在相同的一对实例之间交换数据,但选择了相反的锁定顺序,从而导致死锁。

2024-12-26 10:16:25 571

原创 C++并发编程实战(二):线程管理

一旦线程完成并且join()返回后,std::thread对象将不再关联任何线程,因此不能再次调用join()。如果std::thread对象在其析构之前没有被join()或detach(),那么析构函数会调用std::terminate()终止程序。因此,必须确保在线程对象销毁之前,要么join()要么detach()。如果std::thread对象没有关联任何执行线程(例如,它已经被join()或detach()),则get_id()将返回默认构造的std::thread::id值,表示“没有线程”。

2024-12-25 11:47:21 847

原创 Modern Effective C++ 条款四十二:考虑使用置入代替插入

考虑一个例子,如果尝试将 nullptr 添加到 std::vector<std::regex> 中,emplace_back 会成功编译,而 push_back 则不会,因为 std::regex 的构造函数是 explicit 的,不允许从 nullptr 进行隐式转换。这种场景不容易描述,因为依赖于传递的实参的类型、使用的容器、置入或插入到容器中的位置、容器中类型的构造函数的异常安全性,和对于禁止重复值的容器(即。时,没有理由期望置入比插入运行的更快,因为不需要创建临时对象来满足插入的接口。

2024-12-10 20:18:09 755

原创 Modern Effective C++ 条款四十一:对于移动成本低且总是被拷贝的可拷贝形参,考虑按值传递

对于特殊的场景,可拷贝且移动开销小的类型,传递给总是会拷贝他们的一个函数,并且切片也不需要考虑,这时,按值传递就提供了一种简单的实现方式,效率接近传递引用的函数,但是避免了传引用方案的缺点。然而,由于移动操作通常比拷贝更轻量级,特别是对于大型对象或者资源管理类(如std::string),这种额外的开销通常是可接受的。(3)高效利用现代C++特性:得益于C++11的移动语义,当传入的是右值时,newName会通过移动构造而不是复制构造初始化,从而提高了性能。为了提高效率,应该拷贝左值,移动右值。

2024-12-10 19:42:22 933

原创 Modern Effective C++ 条款四十:对于并发使用std::atomic,对于特殊内存使用volatile

但是在编译器拿到看起来合理的代码,执行了模板实例化,内联和一系列重排序优化之后,结果会出现冗余访问和无用存储,所以编译器需要摆脱这样的情况并不少见。由于auto推导出的y是一个普通的int类型,它不受volatile的影响,因此对y的操作可以被优化。对象被构建,在其上的操作表现得像操作是在互斥锁保护的关键区内,但是通常这些操作是使用特定的机器指令实现,这比锁的实现更高效。对象,这也是默认的和唯一的一致性模型。那些不那么相同,但是如果我们暂时忽略它,只关注编译器执行的操作,则概念上可以说,编译器看到这个,

2024-12-10 10:48:47 796

原创 Modern Effective C++ 条款三十九:对于一次性事件通信考虑使用void的futures

虽然 std::promise 和 std::future 提供了一种简洁且有效的线程间通信方式,并解决了条件变量和标志位设计中的某些问题,但它们也有自己的局限性和适用范围。即使检测任务和反应任务之间没有共享数据的竞争,我们仍然需要互斥锁来防止所谓的“竞态条件”,即检测任务可能在反应任务检查条件之前改变了条件,但又在反应任务开始等待之前再次改变条件。这种情况下,反应任务可能会错过通知。使用共享的布尔型 flag 进行线程间通信的方法确实避免了条件变量设计中的一些复杂性,如互斥锁的需要和虚假唤醒的问题。

2024-12-09 21:53:22 780

原创 Modern Effective C++ 条款三十八:关注不同线程句柄的析构行为

这样的设计使得即使原始的std::promise和第一个std::future被销毁后,其他std::shared_future实例仍然能够访问结果,只要还有至少一个std::future或std::shared_future存在,共享状态就会保持有效,确保只可移动类型的结果可以被正确处理,因为移动操作不会影响共享状态中的实际数据。(1)关联到由 std::async 创建的共享状态:意味该 future 是通过调用 std::async 来创建的,而 std::async 通常用于启动异步任务。

2024-12-08 10:58:42 670

原创 Modern Effective C++ 条款三十七:使std::thread在所有路径最后都不可结合

调用 detach() 后,std::thread 对象不再跟踪这个线程的状态,且不能再次通过这个对象来管理和访问该线程。已调用 detach():当你调用 detach() 方法时,它将分离 std::thread 和底层线程之间的关系,使得线程可以独立运行,而 std::thread 对象不再跟踪这个线程的状态。当一个处于可结合状态的std::thread对象被销毁时(即其析构函数被调用),如果这个线程还没有被join或detach,那么程序将调用std::terminate,导致程序异常终止。

2024-12-07 23:16:41 878

原创 Modern Effective C++条款三十六:如果有异步的必要请指定std::launch::async

如果任务是在不同的线程上执行的,那么它可能会访问到该线程的thread_local 变量的不同实例,这可能导致意外的行为或错误。为了避免这些问题,如果你的任务逻辑中涉及 thread_local 变量,最好显式指定 std::launch::async 策略来确保任务始终在一个新的线程上异步执行,或者重构你的代码以避免对 thread_local 变量的依赖。(4) 影响 thread_local 变量:因为不知道哪个线程会执行任务,所以也就不知道哪个线程的 thread_local 变量会被访问。

2024-12-05 17:52:03 679

原创 Modern Effective C++条款三十五:优先考虑基于任务的编程而非基于线程的编程

它可以代表一个正在运行的软件线程,也可以是未关联任何线程的空句柄(如默认构造的std::thread)。访问底层线程API:当需要使用非常基础的线程功能或操作系统级别的特性(如线程优先级、亲和性等),std::thread提供的native_handle成员函数可以直接访问底层API,而std::future不具备这种能力。(1)线程限额:操作系统能够支持的线程数量是有限的。实现特殊线程技术:当需要使用C++并发API之外的技术(如未被支持的平台上的线程池)时,std::thread提供了更大的灵活性。

2024-12-05 17:25:11 902

原创 Modern Effective C++条款三十四:考虑lambda而非std::bind

当使用steady_clock::now() + 1h作为std::bind的一个参数时,这个表达式是在std::bind被调用的那一刻就被计算(即立即求值),而不是在最终调用setAlarm时计算。当执行 std::bind(&std::chrono::steady_clock::now)时,实际上在创建一个函数对象,不带任何参数,并且当这个函数对象被调用时,会调用 steady_clock::now() 来获取当前的时间点。在C++11中,std::bind可用于模拟移动捕获和创建多态函数对象。

2024-12-05 16:27:20 925

原创 Modern Effective C++ 条款32&33:使用初始化捕获来移动对象到闭包中 / 对auto&&形参使用decltype以std::forward它们

C++11闭包捕获机制仅支持按值或按引用捕获变量,这使得对于只能移动的对象(如std::unique_ptr或std::future)的处理变得困难。此外,对于复制开销高的对象,C++11无法直接实现更高效的移动语义来代替复制。C++14引入了初始化捕获(也称为通用lambda捕获),使得开发者可以将表达式的结果直接作为闭包的数据成员进行初始化,并且允许使用std::move将不可复制的对象移动到闭包中。这种新形式的捕获为开发者提供了更大的灵活性和效率。

2024-12-04 17:17:05 576

原创 Modern Effective C++ 条款三十一:避免使用默认捕获模式

因此,lambda表达式访问的局部变量在整个操作期间都是有效的,不存在悬空引用的风险。这种情况下,默认按引用捕获模式([&])是安全的,因为此时lambda表达式的生命周期与父函数中局部变量的生命周期是一致的。比如,如果一个变量是在lambda创建后很快就会销毁的局部变量,那么按值捕获可能是更好的选择,以确保lambda内部持有该变量的一个独立副本。默认按引用捕获模式可能会带来悬空引用的问题,而默认按值捕获模式也没有解决这个问题,还会让你以为你的闭包是独立的(事实上也不是独立的)。

2024-12-04 16:08:00 794

原创 Modern Effective C++ 条款二十九&三十:移动语义和完美转发失败的情况

告诉编译器某个实体(变量,函数,类等)的名称和类型,不为其分配存储空间。不仅告诉编译器实体的名称和类型,还为其分配存储空间,并可能提供初始化值或实现。static const 整型数据成员的特殊情况。对于static const整型数据成员,可以在类内部进行初始化,但这实际上是声明的一部分。编译器会将这个常量的值传播到所有使用它的地方,从而不需要为它分配实际的存储空间。

2024-12-03 11:29:21 1312

原创 Modern Effective C++ 条款二十八:理解引用折叠

static_cast<Widget&&>(param) 将 param 转换为右值引用,即使 param在std::forward 内部是一个左值引用,但通过 static_cast<Widget&&>(param),它被转换为右值引用。但是编译器没有报错。存在两种类型的引用(左值和右值),所以有四种可能的引用组合(左值的左值,左值的右值,右值的右值,右值的左值)。T 是一个模板参数,std::remove_reference<T>::type 用来去除 T 中可能存在的引用类型,从而得到原始类型。

2024-12-02 15:45:00 926

原创 Modern Effective C++ 条款二十七:熟悉通用引用重载的替代方法

第一个构造函数接受std::string类型的参数,并使用std::move来转移所有权,允许编译器进行潜在的优化。std::is_integral<std::remove_reference_t<T>>::value 确保T不是整型。这个类型参数通常是一个std::true_type或std::false_type,是标准库提供的类型,用于表示布尔值。使用 std::is_base_of 和 std::is_integral,std::is_base_of 用于检查类型是否是 Person 或其派生类。

2024-12-02 13:53:14 747

原创 Modern Effective C++ 条款二十六:避免在通用引用上重载

如果用户尝试用非int类型的整数(例如short, long, std::size_t等)来创建Person对象,编译器会优先选择模板化的完美转发构造函数,而不是预期的int构造函数。因此,传递这些整数类型会导致调用模板构造函数,进而可能导致编译错误,因为std::string没有接受这些整数类型的构造函数。当调用logAndAdd并传入short类型的索引时,编译器会优先选择T&&版本的logAndAdd,因为short可以直接绑定到T&&上,而不需要转换。标签分派可以帮助编译器选择正确的构造函数实现。

2024-12-02 10:17:15 995

原创 Modern Effective C++ 条款二十五:对右值引用使用std::move,对通用引用使用std::forward

对于右值引用,同但在某些情况下,应该使用std::move_if_noexcept而不是std::move,以确保在移动构造函数不可用或抛出异常时仍能安全地进行拷贝。有一个形参,因此需要两种重载实现,但是对于有更多形参的函数,每个都可能是左值或右值,重载函数的数量几何式增长:n个参数的话,就要实现2^n种重载。当你有一个按值返回的函数,其中返回值绑定到一个右值引用上时,应该使用std::move来确保执行移动操作,从而提高效率。在按值返回的函数中使用std::move和std::forward。

2024-11-30 12:22:27 1045

原创 Modern Effective C++ 条款二十四:区分通用引用与右值引用

Args&&... args 是一个通用引用,因为形式是 type&&,并且 Args 的类型会在每次调用时被推导。初始值决定引用类型:通用引用的初始值决定了它是左值引用还是右值引用。MyTemplateType 可以是任何类型,param 是一个通用引用,因为其形式是 type&&,并且 MyTemplateType 的类型会在调用时被推导。auto&& 声明的变量是通用引用,因为会发生类型推导,并且形式是 type&&。当 T&& 用在一个有类型推导的地方时,它被称为通用引用或转发引用。

2024-11-30 11:39:25 701

原创 Modern Effective C++ 条款二十三:理解std::move和std::forward

在模板函数 logAndProcess 中,如果不使用 std::forward<T>(param) 而直接使用 param,那么无论传递给 logAndProcess 的是左值还是右值,param 都会被视为左值。std::forward 是一个有条件的转换,只有当传递给它的参数是右值时,它才会将参数转换为右值引用。使用 std::forward 在模板中转发参数时,保持参数的原始值类别。(2)std::move 不保证移动:std::move 只是将对象转换为右值引用,但并不保证实际的移动会发生。

2024-11-30 10:50:19 1037

原创 Modern Effective C++ 条款二十二:当使用Pimpl惯用法,请在实现文件中定义特殊成员函数

使用std::shared_ptr的差异:如果使用std::shared_ptr而不是std::unique_ptr,则不需要在头文件中声明析构函数,因为std::shared_ptr的删除器类型不是智能指针的一部分,因此它可以在不完整类型上工作。如果使用std::unique_ptr,需要显式地声明析构函数并在实现文件中定义它,以确保在销毁std::unique_ptr前Impl已被定义。由于std::unique_ptr的删除器类型是其一部分,编译器需要知道完整的类型信息来生成正确的删除代码。

2024-11-28 23:27:49 835

原创 Modern Effective C++条款二十一:优先考虑使用std::make_unique和std::make_shared,而非直接使用new

如果computePriority()抛出异常,由于std::make_shared已经成功创建了std::shared_ptr,并且这个智能指针已经开始管理Widget对象,所以在异常处理过程中,std::shared_ptr的析构函数会被调用,从而释放Widget对象占用的内存。对于大型对象,如果使用std::make_shared,则对象的内存会在最后一个std::shared_ptr和最后一个std::weak_ptr都被销毁后才释放。如果需要指定自定义删除器,则必须直接使用new。

2024-11-28 19:37:10 830

原创 Modern Effective C++ 条款二十:当std::shared_ptr可能悬空时使用std::weak_ptr

如果缓存直接使用std::shared_ptr来存储对象,那么即使所有客户端都释放了它们的std::shared_ptr,缓存中的std::shared_ptr仍然会保持对象的存活,导致内存泄漏。效率比较:std::shared_ptr和std::weak_ptr在大多数实现中具有相同的大小,因为它们都存储了一个指向控制块的指针。赋值:将一个std::weak_ptr赋值给另一个std::weak_ptr时,源std::weak_ptr的弱引用计数减少1,目标std::weak_ptr的弱引用计数增加1。

2024-11-28 14:06:40 644

原创 Modern Effecive C++ 条款十九:对于共享资源使用std::shared_ptr

如果Widget对象已经被std::shared_ptr管理,那么将this传递给emplace_back会创建一个新的std::shared_ptr,这可能导致多重控制块问题(即多个std::shared_ptr管理同一个对象)。引用计数本身是存储在独立于所管理对象的内存块中的。(2)独占资源:如果不需要共享所有权,使用 std::unique_ptr 更合适,因为它具有接近原始指针的性能,并且可以从 std::unique_ptr 转换为 std::shared_ptr,反之则不行。

2024-11-27 21:53:19 515

原创 Modern Effective C++ 条款十八:对于独占资源使用std::unique_ptr

拷贝一个std::unique_ptr是不允许的,因为如果你能拷贝一个std::unique_ptr,会得到指向相同内容的两个std::unique_ptr,每个都认为自己拥有(并且应当最后销毁)资源,销毁时就会出现重复销毁。推荐使用 std::array、std::vector 或 std::string。数组管理:std::unique_ptr<T[]>用于管理动态分配的数组,但通常建议使用std::array、std::vector或std::string等容器代替原始数组。模板参数包:Ts&&…

2024-11-27 20:15:55 1377

原创 Modern Effective C++ 条款16&17:确保const成员函数线程安全条款&&特殊成员函数的生成

如果类没有任何用户定义的拷贝或移动操作,并且没有用户定义的析构函数,那么编译器可以自动生成移动构造函数和移动赋值运算符。默认情况下,这两个函数都会执行逐成员的移动操作,即调用每个成员的移动构造函数或移动赋值运算符。如果要让旧的C++98代码支持移动语义,需要使用C++11标准,并在类中添加相应的移动构造函数和移动赋值运算符。,它们是非虚的,除非相关函数是在派生类中的析构函数,派生类继承了有虚析构函数的基类。移动操作仅在需要的时候生成,如果生成了,就会对类的non-static数据成员执行逐成员的移动。

2024-11-27 19:23:18 722

nwpu vlsi复习资料

nwpu vlsi复习资料

2025-01-28

二叉树和链表.docx

二叉树和链表.docx

2024-03-19

eclipse连接hadoop

eclipse连接hadoop所需的配置文件和jar包。 使用说明: 参考博文:https://www.cnblogs.com/supiaopiao/p/7240308.html Tips: 上面网站中的第六步,打开eclipse的右上角有个田字格,选择Map/Reduce。 可能存在没有Map/Reduce字样的情况 解决方法: https://www.cnblogs.com/2016-zck/p/10298631.html

2022-05-16

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除