该项目是 OceanBase 团队基于华中科技大学数据库课程原型,联合多所高校重新开发的、从零上手数据库的学习项目。它结构简单、代码简洁,不仅有文字讲解和视频教程,还有由浅入深的题目。通过理论+实战的方式,帮忙初学者迅速掌握内核模块功能和协同关系,提高工程编码能力,有助于在面试和工作中脱颖而出。
该项目提供了一种新颖的数据传输方式,通过显示条形码并使用摄像头进行传输,无需网络或蓝牙连接。它使用 C++ 编写,并依赖 OpenCV 和 GLFW 等库,内置的编码器可以生成类似二维码的动态动画,用户在手机上安装解码应用后,通过摄像头扫描即可成功接收数据,传输文件的最大限制为 33 MB。
这是一个全面的自动驾驶开源项目,可用于开发和控制多种类型的无人驾驶系统。 它提供了导航、躲避障碍物、飞行控制等自动驾驶功能,支持多种类型的车辆系统、硬件平台和传感器,适用于无人机、无人车、无人船和无人潜艇等无人驾驶系统的开发与研究。
这是一款强大且完全免费,无需注册、没有广告、试用期和商用限制的数字绘画工具,让每一位画师都可以自由地进行创作。它可用于绘制概念草图、插画、漫画、动画、接景和 3D 贴图,支持数位板、压感、防抖、图层、滤镜、色彩管理等功能,适用于 Windows、Linux、macOS 操作系统。
为什么clion的控制台里面输入不了中文,但是可以用剪切板粘贴 !"image.png" (https://wmlx-new-image.oss-cn-shanghai.aliyuncs.com/images/20250121/d2ab415bbaf44de623a791f843082844.png) 我在使用clion学习c++的时候,使用cin>> 想在控制台输入中文但是输不进去 https://wmlx-new-image.oss-cn-shanghai.aliyuncs.com/images/20250121/628596e61dc76277351332f9c4bd3135.png 换过输入法,搜狗qq都试过,在网上也没找到相关资料, 我感觉是因为,输入法打汉字时要先输入字母,然后在把字母替换,但是控制台里面好像没法输入字母 "找到的另一个类似的回答,评论区的朋友研究觉得是版本问题,可能全家桶都出了这个问个题" (https://link.segmentfault.com/?enc=MBY6pPBcu%2Fni1AFHpcdP1w%3D%3D.6FZvDnq0kV%2Fp34oPz9SV7snoS9x%2BtMWQv1B0dkZBif2uvUoztVlZ37g0P9GJAoWrQstPzNUBMvKyfJw09rAozg%3D%3D)
╰─➤ ldd libx264-2881b7ff.so.164 linux-vdso.so.1 (0x00007fff1bec0000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9f37919000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f37d5c000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9f37d57000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f37600000) /lib64/ld-linux-x86-64.so.2 (0x00007f9f37d77000) 比如上面的输出,哪些是「绝对」,哪些是「相对」呢? 我觉得 "/lib64/ld-linux-x86-64.so.2 (0x00007f9f37d77000)" 是绝对 "linux-vdso.so.1 (0x00007fff1bec0000)" 是相对 但是类似 "libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f37d5c000)" 这样的算绝对还是相对引用呢?这里的 "=>" 表示什么含义呢? *** 我有一个问题,就是「如果没有 / ,那么就按找一个特定的方式在在磁盘上寻找这个文件。这个时候,ldd 会用 => 显示寻找的结果。」,我安装了一个 pyav,通过 "pip install av" 安装,然后我查看 av 的一个动态链接库 "ldd _core.cpython-310-x86_64-linux-gnu.so" ,发现这个动态链接库里面的 => 都是指向 "/home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs" 里面的某个文件,我不清楚这个「特定的方式」是什么? (svddb_sdk) ╭─pon@admini ~/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av ╰─➤ ldd _core.cpython-310-x86_64-linux-gnu.so linux-vdso.so.1 (0x00007ffc8db53000) libavformat-20d4e1d0.so.59.27.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavformat-20d4e1d0.so.59.27.100 (0x00007fd001254000) libavcodec-8a88085f.so.59.37.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavcodec-8a88085f.so.59.37.100 (0x00007fcffff37000) libavdevice-ed40abdd.so.59.7.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavdevice-ed40abdd.so.59.7.100 (0x00007fcffff18000) libavutil-1701948d.so.57.28.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavutil-1701948d.so.57.28.100 (0x00007fcfffd3a000) libavfilter-2d5314ec.so.8.44.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavfilter-2d5314ec.so.8.44.100 (0x00007fcfff8e9000) libswscale-a6aee226.so.6.7.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libswscale-a6aee226.so.6.7.100 (0x00007fcfff846000) libswresample-b868a3ce.so.4.7.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libswresample-b868a3ce.so.4.7.100 (0x00007fcfff824000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fcfff7f5000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcfff603000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fcfff4b4000) libxml2-47a785fa.so.2.9.13 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxml2-47a785fa.so.2.9.13 (0x00007fcfff328000) libbluray-69850b93.so.2.1.2 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libbluray-69850b93.so.2.1.2 (0x00007fcfff2d3000) libgmp-dbb9f291.so.10.4.1 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libgmp-dbb9f291.so.10.4.1 (0x00007fcfff25a000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fcfff23e000) libgnutls-58994bd7.so.30.31.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libgnutls-58994bd7.so.30.31.0 (0x00007fcfff005000) libvpx-c1705a7a.so.7.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libvpx-c1705a7a.so.7.0.0 (0x00007fcffedf0000) liblzma-f3a5963b.so.5.2.5 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/liblzma-f3a5963b.so.5.2.5 (0x00007fcffedc5000) libdav1d-df61568f.so.5.1.1 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libdav1d-df61568f.so.5.1.1 (0x00007fcffebff000) libopencore-amrwb-9db94aa9.so.0.0.3 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libopencore-amrwb-9db94aa9.so.0.0.3 (0x00007fcffebe9000) libaom-e9efed4a.so.3.2.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libaom-e9efed4a.so.3.2.0 (0x00007fcffe4a9000) libmp3lame-3ecc6556.so.0.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libmp3lame-3ecc6556.so.0.0.0 (0x00007fcffe415000) libopencore-amrnb-393dbae2.so.0.0.3 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libopencore-amrnb-393dbae2.so.0.0.3 (0x00007fcffe3e7000) libopenjp2-0d101c52.so.2.4.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libopenjp2-0d101c52.so.2.4.0 (0x00007fcffe363000) libopus-70bda348.so.0.8.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libopus-70bda348.so.0.8.0 (0x00007fcffe307000) libspeex-b6a53f7a.so.1.5.1 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libspeex-b6a53f7a.so.1.5.1 (0x00007fcffe2eb000) libtheoraenc-276df146.so.1.1.2 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libtheoraenc-276df146.so.1.1.2 (0x00007fcffe2a9000) libtheoradec-f01ee89e.so.1.1.4 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libtheoradec-f01ee89e.so.1.1.4 (0x00007fcffe287000) libtwolame-72d74ef7.so.0.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libtwolame-72d74ef7.so.0.0.0 (0x00007fcffe25e000) libvorbis-f4a9a6fd.so.0.4.9 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libvorbis-f4a9a6fd.so.0.4.9 (0x00007fcffe221000) libvorbisenc-0d9d5bdf.so.2.0.12 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libvorbisenc-0d9d5bdf.so.2.0.12 (0x00007fcffe170000) libx264-2881b7ff.so.164 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libx264-2881b7ff.so.164 (0x00007fcffde4d000) libx265-d8690e8d.so.199 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libx265-d8690e8d.so.199 (0x00007fcffcbc1000) libxvidcore-d29bca61.so.4.3 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxvidcore-d29bca61.so.4.3 (0x00007fcffcab3000) libxcb-65da195c.so.1.1.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxcb-65da195c.so.1.1.0 (0x00007fcffc880000) libxcb-shm-7a199f70.so.0.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxcb-shm-7a199f70.so.0.0.0 (0x00007fcffc679000) libxcb-shape-25c2b258.so.0.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxcb-shape-25c2b258.so.0.0.0 (0x00007fcffc472000) libxcb-xfixes-9be3ba6f.so.0.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libxcb-xfixes-9be3ba6f.so.0.0.0 (0x00007fcffc262000) libpostproc-9d3ac700.so.56.6.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libpostproc-9d3ac700.so.56.6.100 (0x00007fcffc240000) libass-8499ab98.so.9.1.3 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libass-8499ab98.so.9.1.3 (0x00007fcffc1fe000) libfontconfig-99ba2620.so.1.12.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libfontconfig-99ba2620.so.1.12.0 (0x00007fcffc1aa000) libfreetype-19bd6cfb.so.6.17.1 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libfreetype-19bd6cfb.so.6.17.1 (0x00007fcffc0f9000) /lib64/ld-linux-x86-64.so.2 (0x00007fd0014fe000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fcffc0f1000) libunistring-aeeab030.so.2.1.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libunistring-aeeab030.so.2.1.0 (0x00007fcffbf6a000) libnettle-cb75a9d6.so.8.4 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libnettle-cb75a9d6.so.8.4 (0x00007fcffbf1f000) libhogweed-5d799758.so.6.4 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libhogweed-5d799758.so.6.4 (0x00007fcffbece000) libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fcffbcec000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fcffbccf000) libogg-bbd52b06.so.0.8.5 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libogg-bbd52b06.so.0.8.5 (0x00007fcffbcc3000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fcffbcb9000) libXau-00ec42fe.so.6.0.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libXau-00ec42fe.so.6.0.0 (0x00007fcffbab4000) libfribidi-baef595b.so.0.4.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libfribidi-baef595b.so.0.4.0 (0x00007fcffba91000) libharfbuzz-d40f381a.so.0.40100.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libharfbuzz-d40f381a.so.0.40100.0 (0x00007fcffb97d000) libuuid-f64cda11.so.1.3.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libuuid-f64cda11.so.1.3.0 (0x00007fcffb777000) libpng16-1f529098.so.16.37.0 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libpng16-1f529098.so.16.37.0 (0x00007fcffb746000) 比如其中的 "libavformat-20d4e1d0.so.59.27.100 => /home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavformat-20d4e1d0.so.59.27.100 (0x00007fd001254000)" 这个是按照什么规定让 "libavformat-20d4e1d0.so.59.27.100" 指向 "/home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/libavformat-20d4e1d0.so.59.27.100 (0x00007fd001254000)" 的呢?按理来说,"/home/pon/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av/./../av.libs/" 不应该存在于系统的默认搜索路径中吧?而且我也没有添加类似 LD_LIBRARY_PATH、LD_PRELOAD、LD_LIBRARYN、LD_DEBUG、LD_BIND_NOW 的环境变量 (svddb_sdk) ╭─pon@admini ~/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av ╰─➤ printenv | grep LD_ 1 ↵ (svddb_sdk) ╭─pon@admini ~/.local/share/virtualenvs/svddb_sdk-qAt4tE2E/lib/python3.10/site-packages/av *** 如果使用 readelf 查看,就是下面这样 ─➤ readelf -d _core.cpython-310-x86_64-linux-gnu.so 1 ↵ Dynamic section at offset 0x2d000 contains 33 entries: Tag Type Name/Value 0x000000000000000f (RPATH) Library rpath: [$ORIGIN/../av.libs] 0x0000000000000001 (NEEDED) Shared library: [libavformat-20d4e1d0.so.59.27.100] 0x0000000000000001 (NEEDED) Shared library: [libavcodec-8a88085f.so.59.37.100] 0x0000000000000001 (NEEDED) Shared library: [libavdevice-ed40abdd.so.59.7.100] 0x0000000000000001 (NEEDED) Shared library: [libavutil-1701948d.so.57.28.100] 0x0000000000000001 (NEEDED) Shared library: [libavfilter-2d5314ec.so.8.44.100] 0x0000000000000001 (NEEDED) Shared library: [libswscale-a6aee226.so.6.7.100] 0x0000000000000001 (NEEDED) Shared library: [libswresample-b868a3ce.so.4.7.100] 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000c (INIT) 0x3000 0x000000000000000d (FINI) 0x63c4 0x0000000000000019 (INIT_ARRAY) 0x8cd8 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x8ce0 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0xb358 0x0000000000000005 (STRTAB) 0x12250 0x0000000000000006 (SYMTAB) 0xa8d8 0x000000000000000a (STRSZ) 2479 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000003 (PLTGOT) 0x9000 0x0000000000000002 (PLTRELSZ) 2016 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x1e40 0x0000000000000007 (RELA) 0x17b0 0x0000000000000008 (RELASZ) 1680 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000006ffffffe (VERNEED) 0x16b0 0x000000006fffffff (VERNEEDNUM) 8 0x000000006ffffff0 (VERSYM) 0x15ce 0x000000006ffffff9 (RELACOUNT) 44 0x0000000000000000 (NULL) 0x0
"image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/images/20241222/ef0cdfa83c511a592582e49b76aecfef.png) "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/images/20241222/e7a57d8f9ba8d3cc427881e06589f88c.png) 一道很简单的二重积分问题,请问大佬,不按对称性的解法,按常规解法怎么算出结果的? 我算的总是不对... 还有对称性的解法, 为什么关于y = 0对称就能推出上图的表达式。 没找到对称性关于这点的知识点。 "45a554ef38e56a64d4e534dff2566cb.jpg" (https://wmprod.oss-cn-shanghai.aliyuncs.com/images/20241222/6895db72b2458e7b6fb6b37870ebb550.png)
需求:实现将数组中所有元素调整为左右两部分,左边为奇数,右边为偶数。(c语言)
int main(){
int size;
printf("enter the size of arr:");
scanf("%d",&size);
int arr[size];
for(int i;i 需求:编制C/C++程序,利用顺序存储方式实现下列功能:从键盘输入数据建立一个线性表(整数),并输出该线性表;然后根据屏幕提示,进行数据的插入或删除等操作,并在插入或删除数据后输出线性表。
代码出现问题,无法运行,错误提醒是delete那块红了,估计是它出问题。
未知是什么原因,望指教。
typedef struct {
int data[MAX_SIZE];
int length;
} SeqList;
void init(SeqList *list) {
list->length = 0;
}
void insert(SeqList *list, int position, int value) {
if (position list->length || list->length == MAX_SIZE) {
printf("The insert position is invalid or the linear table is full:\n");
return;
}
for (int i = list->length - 1; i >= position; i--) {
list->data[i + 1] = list->data[i];
}
list->data[position] = value;
list->length++;
}
void delete(SeqList *list, int position) {
if (position = list->length) {
printf("Invalid delete location:\n");
return;
}
for (int i = position; i length - 1; i++) {
list->data[i] = list->data[i + 1];
}
list->length--;
}
void print(SeqList *list) {
printf("Linear table contents:");
for (int i = 0; i length; i++) {
printf("%d ", list->data[i]);
}
printf("\n");
}
int main() {
SeqList list;
init(&list);
printf("Please enter the length of the linear table:");
scanf("%d", &list.length);
if (list.length > MAX_SIZE) {
printf("The linear table length exceeds the maximum value:\n");
return 0;
}
printf("Enter the elements of the linear table:");
for (int i = 0; i < list.length; i++) {
scanf("%d", &list.data[i]);
}
print(&list);
int operation, position, value;
printf("\nplese select:\n"); printf("1. insect the data:\n");
printf("2. delete the data\n");
printf("0. exit\n");
while (1) {
printf("\nplease enter the ops:");
scanf("%d", &operation);
if (operation == 1) {
printf("Please enter insert position and insert value (separated by space):");
scanf("%d %d", &position, &value);
insert(&list, position, value);
} else if (operation == 2) {
printf("Please enter the deletion location:");
scanf("%d", &position);
delete(&list, position);
} else if (operation == 0) {
break;
} else {
printf("Invalid operation number:\n");
}
print(&list);
}
return 0;
}
顺便提问一句我的DEVC++底下变成这样,应该怎么恢复到初始可以看见报错原因的状态?
"image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/images/20241228/8f98052c1059aa39d58623656470276e.png)
菜鸟上路,万分感谢指教。 线程同步操作:C++ 标准库提供了以下几种线程同步的方式:互斥量(支持超时加锁、递归加锁);读写锁(共享互斥量,也支持超时加锁);互斥量包装器(基于 RAII 的思想);条件变量;信号量(二元信号量、计数信号量);barrier;call_once;不同的同步方式具有不同的使用场景和性能,实际使用时根据不同的场景选择不同的同步方式,分别就几种以上几种方式进行简要介绍:1.互斥量(mutex):互斥量(mutex)是防止同时访问共享资源的程序对象。为避免线程更新共享变量时所出现问题,必须使用互斥量(mutex 是 mutual exclusion 的缩写)来确保同时仅有一个线程可以访问某项共享资源。 即使用互斥量来实现原子访问操作,防止多个线程对临界区同时操作而产生不一致的问题。mutex 只有锁定(locked)和未锁定(unlocked)两种状态。任何时候,至多只有一个线程可以锁定互斥量。试图对已经锁定的互斥量再次加锁,将可能阻塞线程或者报错失败,mutex 的底层可能封装的是操作系统 spinlock,不同的操作系统下可能有不同的实现。C++ 中关于 mutex 的头文件为 #include <mutex>。C++#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_block (int n, char c) {
mtx.lock();
for (int i=0; i<n; ++i) { std::cout << c; }
std::cout << '\n';
mtx.unlock();
}
int main ()
{
std::thread th1 (print_block,50,'*');
std::thread th2 (print_block,50,'$');
th1.join();
th2.join();
return 0;
}
/*
****************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
*/C++ 中还定义了 timed_mutex:在 mutex 的基础上增加了超时加锁的功能。recursive_mutex:在 mutex 的基础上增加了递归加锁的功能(此时,lock() 函数可以被同一线程在不释放锁的情况下多次调用)。C++std::recursive_mutex mtx;
void fun1() {
mtx.lock();
mtx.unlock();
}
void fun2() {
mtx.lock();
fun1(); // recursive lock
mtx.unlock();
};2.共享互斥量:std::shared_mutex 是 C++ 17 标准中引入的,由 unique_lock 和 shared_lock 两个类模板配合 shared_mutex 使用,主要用于读写共享锁。unique_lock 用于写入时加锁,shared_lock 用于读取时加锁。对象在构造时自动对 std::shared_mutex 加锁,析构时自动对其解锁。头文件主要包含在 #include <shared_mutex>。shared_mutex 可用于保护共享数据不被多个线程同时访问。与其他便于独占访问的互斥锁类型相比,shared_mutex 具有两个访问级别:shared:多个线程可以共享同一个互斥锁的所有权。exclusive :只有一个线程可以拥有互斥锁。共享互斥锁通常用于多个读取操作可以同时访问同一资源而不会导致数据竞争,但只有一个写入操作的场景。C++#include <iostream>
#include <mutex> // For std::unique_lock
#include <shared_mutex>
#include <thread>
class ThreadSafeCounter {
public:
ThreadSafeCounter() = default;
// 多个线程可以同时读取 countter 计数
unsigned int get() const {
std::shared_lock lock(mutex_);
return value_;
}
// 只有1个线程可以修改 countter 计数
void increment() {
std::unique_lock lock(mutex_);
value_++;
}
// 只有1个线程可以修改 countter 计数
void reset() {
std::unique_lock lock(mutex_);
value_ = 0;
}
private:
mutable std::shared_mutex mutex_;
unsigned int value_ = 0;
};
int main() {
ThreadSafeCounter counter;
auto increment_and_print = [&counter]() {
for (int i = 0; i < 3; i++) {
counter.increment();
std::cout << std::this_thread::get_id() << ' ' << counter.get() << '\n';
// Note: Writing to std::cout actually needs to be synchronized as well
// by another std::mutex. This has been omitted to keep the example small.
}
};
std::thread thread1(increment_and_print);
std::thread thread2(increment_and_print);
thread1.join();
thread2.join();
}
/*
139677317637888 2
139677317637888 3
139677309245184 4
139677309245184 5
139677309245184 6
139677317637888 6
*/我们可以看到 increment 同时只能有一个线程对计数进行增加,但可能同时存在多个线程读取同一个计数。shared_timed_mutex 是在 shared_mutex 的基础上增加了超时加锁的功能。3.互斥量包装器lock_guard:使用了 RAII 的机制对互斥量进行类模板封装,构造时加锁,析构时解锁。C++#include <mutex>
std::mutex mtx;
void f()
{
const std::lock_guard<std::mutex> lock(mtx);
// ...
// mtx is automatically released when lock goes out of scope
}互斥量包装器对比原生的 mutex 来说,创建即加锁,作用域结束自动析构并解锁,无需手动解锁。缺点是不能中途解锁,不支持复制和移动。在需要加锁的地方,只需要任意实例化一个 lock_guard,调用构造函数成功上锁,出作用域时则 lock_guard 对象会被销毁,调用析构函数自动解锁可以有效避免死锁问题,但是提供的功能单一且不够灵活。unique_lock:unique_lock 类模板也是采用 RAII 的方式对锁进行了封装,并且也是以独占所有权的方式管理 mutex 对象的上锁和解锁操作,即其对象之间不能发生拷贝。在构造(或移动 move 赋值)时,unique_lock 对象需要传递一个 mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 mutex 对象的上锁和解锁操作。使用以上类型互斥量实例化 unique_lock 的对象时,自动调用构造函数上锁,unique_lock 对象销毁时自动调用析构函数解锁,可以很方便的防止死锁问题。与 lock_guard 不同的是,unique_lock 更加的灵活,提供了更多的成员函数:上锁/解锁操作:lock、try_lock、try_lock_for、try_lock_until 和 unlock;修改操作:支持移动赋值、交换(swap:与另一个 unique_lock 对象互换所管理的互斥量所有权)、释放(release:返回它所管理的互斥量对象的指针,并释放所有权)。获取属性:owns_lock (返回当前对象是否上了锁)、operator bool() (与 owns_lock() 的功能相同)、mutex(返回当前 unique_lock 所管理的互斥量的指针)。4.条件变量(condition variable):在 C++ 11 以后,我们可以使用条件变量(condition_variable)实现多个线程间的同步操作;当条件不满足时,相关线程被一直阻塞,直到某种条件出现,这些线程才会被唤醒。C++ 中包含的头文件在 #include <condition_variable> 中。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程因等待 条件变量的条件成立 而挂起;另外一个线程使 条件成立 从而给出唤醒线程的信号,从而唤醒被等待的线程;为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起;通常情况下这个锁是 std::mutex,并且管理这个锁只能是 std::unique_lock std::mutex 等 RAII 模板类。分别是使用以下两个方法实现:等待条件成立使用的是 condition_variable 类成员 wait 、wait_for 或 wait_until。唤醒信号使用的是 condition_variable 类成员 notify_one 或者 notify_all 函数。我们可以看到 wait 函数如下:C++template< class Predicate >
void wait( std::unique_lock<std::mutex>& lock, Predicate stop_waiting );线程会一直挂起,直到 stop_waiting 为 true 为止。程序示例如下:C++#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
std::unique_lock<std::mutex> lk(m);
// worker 线程等待 ready
cv.wait(lk, []{return ready;});
// 唤醒执行
std::cout << "Worker thread is processing data\n";
data += " after processing";
// processed 设置为 true, 唤醒 main 线程
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// 释放锁,防止再次被唤醒。
lk.unlock();
// 唤醒 main 线程
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
// 让 worker 线程先执行,再进行唤醒,否则可能出现 ready = true 先于 worker 线程的执行
worker.detach();
data = "Example data";
// 设置 ready 为 true, 唤醒 worker 线程
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
// 唤醒 worker 线程
cv.notify_one();
// 等待 worker 线程
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
return 0;
}5.信号量:C++ 20 中添加了 C++ 中的信号量为二元信号量与计数信号量,二元信号量实际为计数信号量模板的特化。binary_semaphore:二元信号量类似于互斥量,信号量只有 0 与 1 。counting_semaphore:计数信号量所有关于信号量的定义参考头文件 #include <semaphore>,计数信号量是一种轻量级同步原语,可以控制对共享资源的访问。与 std::mutex 不同的是,acounting_semaphore 至少允许 LeastMaxValue 并发访问者对同一资源进行多个并发访问。Acounting_semaphore 包含一个由构造函数初始化的内部计数器。该计数器可以通过 acquire() 获取资源访问权限,并通过调用 release() 来释放资源从而递增计数器。当计数器为零时,调用 acquire() 时就会阻塞直到计数器增加,但是调用 try_acquire( ) 不阻塞;try_acquire_for() 和 try_acquire_until() 阻塞直到计数器增加或达到超时。C++#include <iostream>
#include <thread>
#include <chrono>
#include <semaphore>
std::binary_semaphore
smphSignalMainToThread{0},
smphSignalThreadToMain{0};
void ThreadProc()
{
// 第一次进入阻塞
smphSignalMainToThread.acquire();
std::cout << "[thread] Got the signal\n"; // response message
using namespace std::literals;
std::this_thread::sleep_for(3s);
std::cout << "[thread] Send the signal\n"; // message
// 唤醒 main 线程
smphSignalThreadToMain.release();
}
int main()
{
std::thread thrWorker(ThreadProc);
std::cout << "[main] Send the signal\n"; // message
// 唤醒 ThreadProc
smphSignalMainToThread.release();
// main 线程阻塞
smphSignalThreadToMain.acquire();
std::cout << "[main] Got the signal\n"; // response message
thrWorker.join();
}
/*
[main] Send the signal
[thread] Got the signal
[thread] Send the signal
[main] Got the signal
*/6.barrier:C++ 20 以后支持 latch 与 barrier,他们同样可以用来线程同步。latch:类 latch 是 std::ptrdiff_t 类型的向下计数器,可用于同步线程。计数器的值在创建时初始化。线程可能会阻塞在锁存器上,直到计数器减为零。不能增加或重置计数器,这使得锁存器创建后不可重用。其内部维护着一个计数器,当计数不为 0 时,所有参与者(线程)都将阻塞在等待操作处,计数为 0 时,解除阻塞。计数器不可重置或增加,故它是一次性的,不可重用。与 std::barrier 不同,std::latch 参与线程可以多次递减。C++#include <latch>
std::latch work_done(4);
work_done.count_down(); // decrements the counter in a non-blocking manner
work_done.wait(); // blocks until the counter reaches zero
bool ok = work_done.try_wait(); // tests if the internal counter equals zero
work_done.arrive_and_wait(); // decrements the counter and blocks until it reaches zerobarrier:类似于 latch,它会阻塞线程直到所有参与者线程都到达一个同步点,直到预期数量的线程到达设定的值则会接触阻塞。与 latch 不同的是,它是可重用的。一个 barrier 的生命周期包含多个阶段,每个阶段都定义了一个同步点。一个 barrier 阶段包含:期望计数(设创建时指定的计数为 n),当期望计数不为 0 时,参与者将阻塞于等待操作处;当期望计数为 0 时,会执行创建 barrier 时指定的阶段完成步骤,然后解除阻塞所有阻塞于同步点的参与者线程。当阶段完成步骤执行完成后,会重置期望计数为 n - 调用arrive_and_drop() 的次数,然后开始下一个阶段。C++#include <barrier>
#include <iostream>
#include <string>
#include <thread>
#include <vector>
int main() {
const auto workers = { "anil", "busara", "carl" };
auto on_completion = []() noexcept {
// locking not needed here
static auto phase = "... done\n" "Cleaning up...\n";
std::cout << phase;
phase = "... done\n";
};
std::barrier sync_point(std::ssize(workers), on_completion);
auto work = [&](std::string name) {
std::string product = " " + name + " worked\n";
std::cout << product; // ok, op<< call is atomic
sync_point.arrive_and_wait();
// 全部到达后,进行下一阶段
product = " " + name + " cleaned\n";
std::cout << product;
sync_point.arrive_and_wait();
};
std::cout << "Starting...\n";
std::vector<std::thread> threads;
for (auto const& worker : workers) {
threads.emplace_back(work, worker);
}
for (auto& thread : threads) {
thread.join();
}
}
/*
Starting...
anil worked
carl worked
busara worked
... done
Cleaning up...
busara cleaned
anil cleaned
carl cleaned
... done
*/7.call_once:C++ 11 以后支持 call_once。确保某个操作只被执行一次(成功执行才算),即使是多线程环境下也确保只执行一次。C++template< class Callable, class... Args >
void call_once( std::once_flag& flag, Callable&& f, Args&&... args );如果在 call_once 被调用时,flag 表明 f 已经被调用,则 call_once 立即返回(这种调用 call_once 称为被动)。C++#include <iostream>
#include <thread>
#include <mutex>
std::once_flag flag1, flag2;
void simple_do_once()
{
std::call_once(flag1, [](){ std::cout << "Simple example: called once\n"; });
}
int main()
{
std::thread st1(simple_do_once);
std::thread st2(simple_do_once);
std::thread st3(simple_do_once);
std::thread st4(simple_do_once);
st1.join();
st2.join();
st3.join();
st4.join();
}
/*
Simple example: called once
*/ 七安前
顺序存储,线性表的删除和插入中出现问题,未知代码哪里出错?
菜鸟码转
2.线程同步与异步