0%

概述

在使用Linux的Socket进行TCP连接时,需要使用Connect进行3次握手以完成连接。其函数原型如下:

1
2
3
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

阻塞状态

当socket处于阻塞状态时,调用Connect将进入阻塞状态,自到三次握手成功或连接失败。

Socket判断连接失败的方式是设置单次握手的超时时间+设置允许超时的次数,Linux通常情况下超时时间呈2的指数次方增长,超时次数设为6次,可以使用sysctl net.ipv4.tcp_syn_retries查看允许超时次数。因此当连接失败时需要等待1s + 2s + 4s + 8s + 16s + 32s + 64s = 127s。该时间明显过长。

当connect连接成功时,将会返回0;当连接失败是,返回-1并设置errno。

非阻塞状态

当socket处于阻塞状态时,调用Connect将立即返回,同时尝试进行三次握手,这使得程序能够在进行握手的同时异步的进行其他事务的处理。

通常情况下,当连接目标非本机时,将会立即返回-1,并设置errnoEINPROGRESS;当连接目标为本机时,立即能够获得连接结果并进行处理。

当进入异步连接状态时,可以通过判断soeket描述符是否可写来判断是否完成连接处理判断。这可以使用select等方式进行处理。

当判断连接完成时,还需要判断连接是否成功。通常情况下,可以通过将getsockopt获取soeket描述符上的错误。

一个简单的非阻塞socket connect demo如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
int socket_connect() {
while(true) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
assert(-1 != sock);

int flag=fcntl(sock, F_GETFL);
assert(-1 != flag);
flag = fcntl(fd,F_SETFL,flag | O_NONBLOCK);
assert(-1 != flag);

struct sockaddr_in addr;
socklen_t addrlen;

bzero(&addr, sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(atoi(port));
flag = inet_pton(AF_INET,ip,&addr.sin_addr.s_addr);
assert(-1 != flag);

int ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));

if(0 == ret) {
return sock;
}

if(errno != EINPROGRESS) {
close(sock);
continue;
}

fd_set writefds;
struct timeval timeout;

timeout.tv_sec = s;
timeout.tv_usec = us;

while(true) {
FD_ZERO(&writefds);
FD_SET(sock, &writefds);

int ret = select(sock + 1, NULL, &writefds, NULL, &timeout);

if(0 == ret) {
onTimeout();
} else if(-1 == ret) {
if(EINTR == errno) {
onTimeout();
} else {
close(sock);
break;
}
} else if(1 == ret) {
if(!FD_ISSET(sock, &writefds)) {
close(sock);
break;
} else {
int error = 0;
socklen_t length=sizeof(error);
ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &length);
if(-1 == ret || 0 != error) {
close(sock);
break;
} else {
return sock;
}
}
} else {
close(sock);
break;
}
}
}
}

为当前用户添加sudo权限

root下编辑/etc/sudoers文件,在文件末尾追加,其中<user>表示要添加用户的标识符:

1
<user>     ALL=(ALL:ALL) ALL

修改apt下载镜像

修改/etc/apt/sources.list文件,将其改为如下内容:

1
2
3
4
5
6
7
8
9
10
11
deb https://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib
deb-src https://mirrors.aliyun.com/debian/ bookworm main non-free non-free-firmware contrib

deb https://mirrors.aliyun.com/debian-security/ bookworm-security main
deb-src https://mirrors.aliyun.com/debian-security/ bookworm-security main

deb https://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib
deb-src https://mirrors.aliyun.com/debian/ bookworm-updates main non-free non-free-firmware contrib

deb https://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib
deb-src https://mirrors.aliyun.com/debian/ bookworm-backports main non-free non-free-firmware contrib

运行sudo apt update刷新缓存。

修改系统语言为中文并添加中文输入法

运行sudo dpkg-reconfigure locales命令,并选择zh_CN.UTF-8作为默认区域设置。

运行如下命令:

1
2
3
sudo apt-get install ibus ibus-clutter ibus-gtk ibus-gtk3 ibus-qt4 -y

sudo apt install ibus-libpinyin -y

重启后在设置中设置中文输入:

安装相关应用

运行如下命令:

1
2
3
4
5
6
7
8
9
10
sudo apt install build-essential manpages-dev git cmake make vim gdb adb valgrind -y

wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo apt install ./google-chrome-stable_current_amd64.deb

wget -q https://packages.microsoft.com/keys/microsoft.asc -O- | sudo apt-key add -
sudo apt install software-properties-common apt-transport-https wget
sudo add-apt-repository "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main"
sudo apt update
sudo apt install code

挂载Win共享磁盘分区

首先保证在win下创建了一个可用于共享的分区。

运行如下命令,获得对应的分区UUID和目标用户的id和对应组id:

1
2
lsblk
id <user>

/etc/fstab下添加:

1
UUID=<UUID> <mount_point> exfat defaults,utf8,uid=<user_id>,gid=<user_group_id>,dmask=022,fmask=133 0 0

于是便完成了开机自动挂载设置。

设置vim禁用鼠标

在vim中输入scriptnames命令查看配置文件列表,并在其中查找包含set mouse命令的文件,在该文件末尾添加:set mouse=

制作系统盘

下载镜像

Debian官网下载系统进行,推荐下载完整镜像。

下载UltralSO

UltraISO官网下载安装包并进行安装。

制作系统镜像

首先插入U盘,打开UltralSO并打开下载好的系统镜像。

之后点击“启动”下的“写入磁盘映像”。

最后,先进行格式化,后进行写入。写入完成后便完成系统盘制作。

划分磁盘空间

  1. 点击“Win+X”,选择磁盘管理:

  2. 右键目标磁盘,选择压缩卷:

  3. 填写压缩量,获得一块连续的未分配空间:

使用系统盘安装系统

  1. 在“设置-安全与更新-恢复-高级启动”处点击“立即重启”:

  2. 在重启的蓝色页面中找到从U盘启动(如果失败则进入bios关闭安全启动)。

  3. 之后按照系统提示操作即可。

具体错误信息

PowerShell中运行wsl命令:

1
2
3
4
5
6
WSL 正在完成升级...
Warning 1946.Property 'System.AppUserModel.ID' for shortcut 'WSL.lnk' could not be set.
Warning 1946.Property 'System.AppUserModel.ToastActivatorCLSID' for shortcut 'WSL.lnk' could not be set.
Could not write value to key \SOFTWARE\Classes\Directory\shell\WSL. Verify that you have sufficient access to that key, or contact your support personnel.
更新失败(退出代码: 1603)。
Error code: Wsl/CallMsi/Install/ERROR_INSTALL_FAILURE

解决方法

  1. 开启依赖项:

    在管理员权限的PowerShell,运行:

    1
    2
    dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
    Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform -NoRestart

    重启Windows 10

  2. 修改注册表:

    键入win+r,打开运行面板,输入regedit,打开注册表编辑器。

    在注册表编辑器中将下述键重命名(最好操作前进行备份):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 将下列键
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Drive\shell\WSL
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\WSL
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\WSL

    // 重命名为
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Drive\shell\WSL_bak
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\background\shell\WSL_bak
    计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\WSL_bak

本节主要是对可变元数据标签的含义和用法进行说明。

This section contains notes about the interpretation and usage of various metadata tags.

S9.1 高质量(HIGH_QUALITY)模式和快速(FAST)模式

许多相机后处理模块可能具有HIGH_QUALITYFASTOFF操作模式。这些模块通常也有一个‘可用模式’标签,用于表示给定设备有哪些操作模式可用。下面是实现这些模式的一般策略:

Many camera post-processing blocks may be listed as having HIGH_QUALITY, FAST, and OFF operating modes. These blocks will typically also have an ‘available modes’ tag representing which of these operating modes are available on a given device. The general policy regarding implementing these modes is as follows:

  1. 无法禁用的硬件模块的操作模式控制器不能将OFF列在其自身的‘可用模式’标签中。

    Operating mode controls of hardware blocks that cannot be disabled must not list OFF in their corresponding ‘available modes’ tags.

  2. 如果硬件模块可以被禁用,OFF将总是包含其具有的‘可用模式’标签中。

    OFF will always be included in their corresponding ‘available modes’ tag if it is possible to disable that hardware block.

  3. 对于设备支持的所有后处理模块,FAST必须始终被包含在对应的‘可用模式’标签中。如果一个后处理模块还有不符合FAST模式帧率要求的更慢、更高质量的操作模式,HIGH_QUALITY应该被包含在对应的‘可用模式’标签中以表示该操作模式。

    FAST must always be included in the ‘available modes’ tags for all post-processing blocks supported on the device. If a post-processing block also has a slower and higher quality operating mode that does not meet the framerate requirements for FAST mode, HIGH_QUALITY should be included in the ‘available modes’ tag to represent this operating mode.

HAL3相机设备被要求支持两种可能操作模式,两种操作模式分别为受限模式和完整模式。高端设备应当支持完整模式。限制模式则被要求其硬件与HAL1版本的设备实现大致相同,并且应当被使用在更老或相对低端的设备中。完整模式应当是受限模式的严格超集,并且都具有文档所示的必要的操作流程。

The camera 3 HAL device can implement one of two possible operational modes; limited and full. Full support is expected from new higher-end devices. Limited mode has hardware requirements roughly in line with those for a camera HAL device v1 implementation, and is expected from older or inexpensive devices. Full is a strict superset of limited, and they share the same essential operational flow, as documented above.

HAL必须在android.info.supportedHardwareLevel静态元数据条目中给出支持的操作模式,为0是表明支持受限模式,为1表示支持完整模式。

The HAL must indicate its level of support with the android.info.supportedHardwareLevel static metadata entry, with 0 indicating limited mode, and 1 indicating full mode support.

粗略的说,受限模式的设备不允许应用控制捕获设置(只支持3A设置)、高分辨率图像的高帧率捕获、读出传感器生成的生数据或高于最大纪录分辨率的YUV输出流支持(JPEG仅适用于大图像)。

Roughly speaking, limited-mode devices do not allow for application control of capture settings (3A control only), high-rate capture of high-resolution images, raw sensor readout, or support for YUV output streams above maximum recording resolution (JPEG only for large images).

限制模式行为的细节:

Details of limited mode behavior:

  • 限制模式设备不需要实现捕获请求设置和实际图像数据被捕获间的精确捕获。相反的,设置的修改将可能会在之后的一段时间后才生效,并可能不会对一个输出帧应用全部的设置条目修改。快速的改变设置可能会导致一些设置从未被任何捕获使用。然而,包含高分辨率输出缓冲区(>1080p)的捕获必须使用指定的设置(关于处理帧率,请参阅下文)。

    Limited-mode devices do not need to implement accurate synchronization between capture request settings and the actual image data captured. Instead, changes to settings may take effect some time in the future, and possibly not for the same output frame for each settings entry. Rapid changes in settings may result in some settings never being used for a capture. However, captures that include high-resolution output buffers ( > 1080p ) have to use the settings as specified (but see below for processing rate).

  • 限制模式设备不需要支持大多数设置/结果/静态元数据信息。特别的,只希望如下设置被限制模式设备消费或制造:

    Limited-mode devices do not need to support most of the settings/result/static info metadata. Specifically, only the following settings are expected to be consumed or produced by a limited-mode HAL device:

    android.control.aeAntibandingMode (controls and dynamic)
    android.control.aeExposureCompensation (controls and dynamic)
    android.control.aeLock (controls and dynamic)
    android.control.aeMode (controls and dynamic)
    android.control.aeRegions (controls and dynamic)
    android.control.aeTargetFpsRange (controls and dynamic)
    android.control.aePrecaptureTrigger (controls and dynamic)
    android.control.afMode (controls and dynamic)
    android.control.afRegions (controls and dynamic)
    android.control.awbLock (controls and dynamic)
    android.control.awbMode (controls and dynamic)
    android.control.awbRegions (controls and dynamic)
    android.control.captureIntent (controls and dynamic)
    android.control.effectMode (controls and dynamic)
    android.control.mode (controls and dynamic)
    android.control.sceneMode (controls and dynamic)
    android.control.videoStabilizationMode (controls and dynamic)
    android.control.aeAvailableAntibandingModes (static)
    android.control.aeAvailableModes (static)
    android.control.aeAvailableTargetFpsRanges (static)
    android.control.aeCompensationRange (static)
    android.control.aeCompensationStep (static)
    android.control.afAvailableModes (static)
    android.control.availableEffects (static)
    android.control.availableSceneModes (static)
    android.control.availableVideoStabilizationModes (static)
    android.control.awbAvailableModes (static)
    android.control.maxRegions (static)
    android.control.sceneModeOverrides (static)
    android.control.aeState (dynamic)
    android.control.afState (dynamic)
    android.control.awbState (dynamic)

    android.flash.mode (controls and dynamic)
    android.flash.info.available (static)

    android.info.supportedHardwareLevel (static)

    android.jpeg.gpsCoordinates (controls and dynamic)
    android.jpeg.gpsProcessingMethod (controls and dynamic)
    android.jpeg.gpsTimestamp (controls and dynamic)
    android.jpeg.orientation (controls and dynamic)
    android.jpeg.quality (controls and dynamic)
    android.jpeg.thumbnailQuality (controls and dynamic)
    android.jpeg.thumbnailSize (controls and dynamic)
    android.jpeg.availableThumbnailSizes (static)
    android.jpeg.maxSize (static)

    android.lens.info.minimumFocusDistance (static)

    android.request.id (controls and dynamic)

    android.scaler.cropRegion (controls and dynamic)
    android.scaler.availableStreamConfigurations (static)
    android.scaler.availableMinFrameDurations (static)
    android.scaler.availableStallDurations (static)
    android.scaler.availableMaxDigitalZoom (static)
    android.scaler.maxDigitalZoom (static)
    android.scaler.croppingType (static)

    android.sensor.orientation (static)
    android.sensor.timestamp (dynamic)

    android.statistics.faceDetectMode (controls and dynamic)
    android.statistics.info.availableFaceDetectModes (static)
    android.statistics.faceIds (dynamic)
    android.statistics.faceLandmarks (dynamic)
    android.statistics.faceRectangles (dynamic)
    android.statistics.faceScores (dynamic)

    android.sync.frameNumber (dynamic)
    android.sync.maxLatency (static)

  • 包含高分辨率输出缓冲区(>1080p)的受限模式设备捕获可能会阻塞在process_capture_request()直到所有输出缓冲区完成填充。一个完全模式的HAL设备必须按照对应像素格式的静态元数据中指定的速率处理高分辨率请求序列。HAL仍将调用process_capture_result()用于提供输出;对于受限模式设备,框架层将简单的阻塞在process_capture_request()直到对应高分辨率捕获请求的process_capture_result()的调用完成。

    Captures in limited mode that include high-resolution (> 1080p) output buffers may block in process_capture_request() until all the output buffers have been filled. A full-mode HAL device must process sequences of high-resolution requests at the rate indicated in the static metadata for that pixel format. The HAL must still call process_capture_result() to provide the output; the framework must simply be prepared for process_capture_request() to block until after process_capture_result() for that request completes for high-resolution captures for limited-mode devices.

  • 完全模式设备必须支持如下额外功能:

    Full-mode devices must support below additional capabilities:

    • 必须在最大分辨率下具有大于20fps的帧率,最好能达到30fps。

      30fps at maximum resolution is preferred, more than 20fps is required.

    • 逐帧控制(android.sync.maxLatency == PER_FRAME_CONTROL

      Per frame control (android.sync.maxLatency == PER_FRAME_CONTROL).

    • 传感器手动控制元数据。详见在android.request.availableCapabilities中定义的MANUAL_SENSOR

      Sensor manual control metadata. See MANUAL_SENSOR defined in android.request.availableCapabilities.

    • 后处理手动控制元数据。详见在android.request.availableCapabilities中定义的MANUAL_POST_PROCESSING

      Post-processing manual control metadata. See MANUAL_POST_PROCESSING defined in android.request.availableCapabilities.

在发生严重错误时,所有有返回值的HAL相机设备操作函数将返回-ENODEVNULL。这表示当前设备不能继续运行并应该被框架层关闭。一旦错误被一些方法返回或notify()被使用ERROR_DEVICE参数调用,则只有close()方法能被成功调用,其他方法都将返回-ENODEVNULL

Camera HAL device ops functions that have a return value will all return -ENODEV / NULL in case of a serious error. This means the device cannot continue operation, and must be closed by the framework. Once this error is returned by some method, or if notify() is called with ERROR_DEVICE, only the close() method can be called successfully. All other methods will return -ENODEV / NULL.

如果设备被以错误的顺序操作,例如框架层在调用initialize()前调用configure_streams(),设备必须对该调用回-ENOSYS并不做其他任何操作。

If a device op is called in the wrong sequence, for example if the framework calls configure_streams() is called before initialize(), the device must return -ENOSYS from the call, and do nothing.

图像捕获过程中的瞬时错误必须按照如下规则通过notify()报告:

Transient errors in image capture must be reported through notify() as follows:

  1. 若整个捕获失败,HAL将通过使用ERROR_REQUEST参数调用notify()进行报告。单独的元数据返回或缓冲区输出错误不会通过该方式报告。

    The failure of an entire capture to occur must be reported by the HAL by calling notify() with ERROR_REQUEST. Individual errors for the result metadata or the output buffers must not be reported in this case.

  2. 如果无法为捕获生成元数据,但已经有图像缓冲区被填充,HAL将通过使用ERROR_RESULT参数调用notify()进行报告。

    If the metadata for a capture cannot be produced, but some image buffers were filled, the HAL must call notify() with ERROR_RESULT.

  3. 如果用于输出的图像缓冲区不能被填充,但已经有元数据被生成或某些其他的缓冲区被填充,HAL将对每个失败的缓冲区通过使用ERROR_BUFFER参数调用notify()进行报告。

    If an output image buffer could not be filled, but either the metadata was produced or some other buffers were filled, the HAL must call notify() with ERROR_BUFFER for each failed buffer.

HAL必须仍然对每个具有瞬时错误的示例使用有效的输出或输入(如果提交了输入缓冲区)的buffer_handle_t调用process_capture_result。当元数据无法生成时,将其字段设为NULL。如果图像缓冲区不能被填充,则必须携带错误状态通过process_capture_result返回,这些缓冲区的释放栅栏必须被设置为传递给框架层的获取栅栏或是-1栅栏(如果它们已经被HAL等待)。

In each of these transient failure cases, the HAL must still call process_capture_result, with valid output and input (if an input buffer was submitted) buffer_handle_t. If the result metadata could not be produced, it should be NULL. If some buffers could not be filled, they must be returned with process_capture_result in the error state, their release fences must be set to the acquire fences passed by the framework, or -1 if they have been waited on by the HAL already.

使用无效参数调用相应的方法时将会返回-EINVAL。在这种情况下,框架层应该表现得像该方法从未被调用过一样。

Invalid input arguments result in -EINVAL from the appropriate methods. In that case, the framework must act as if that call had never been made.

概述

原子变量是一类能保证其各个操作均为线程安全的特殊变量,是无锁编程的基础,在高性能场景中应用十分广泛。

对于普通变量而言,因为对变量的修改需要经历读取-修改-写回等步骤,因此对其的修改不是线程安全的。原子变量使用CAS、总线锁等机制,保证上述各个步骤不会被打断,从而保证操作的线程安全。

CPP提供了std::atomic作为原子变量,它能够接受一个可平凡复制且可移动、拷贝的类型作为模板参数。CPP中,原子变量是不可拷贝和移动的。

通用方法

对于所有合法参数类型,其提供了以下方法:

接口 含义
bool is_lock_free() const noexcept; 检查对该对象的全部操作是否无锁
除了std::atomic_flag外,CPP允许原子变量通过锁定操作来实现,而不是使用无锁原子CPU指令
void store(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept; 使用desired对原子变量赋值
T load(std::memory_order order = std::memory_order_seq_cst) const noexcept; 取出原子变量中的值
operator T() const noexcept; 默认类型转换函数,相当于load()
T exchange(T desired, std::memory_order order = std::memory_order_seq_cst) noexcept; 使用desired对原子变量赋值,并返回原子变量原值
bool compare_exchange_weak(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept;
bool compare_exchange_strong(T& expected, T desired, std::memory_order order = std::memory_order_seq_cst) noexcept;
相当于原子性的执行下述操作if(*this == expected) { auto ret = *this; *this = desired; return true; } else { return false; }
*this和expected间的比较为按位比较,不调用operator==函数
compare_exchange_weak和compare_exchange_strong的区别主要在,为了在某些架构处理器上获得性能优势,compare_exchange_weak被允许产生允许虚假的失败

只适用于整形和指针的方法

接口 含义
T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_add(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的加上参数值,返回原值
T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_sub(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的减去参数值,返回原值
T operator+=(T arg) noexcept;
T* operator+=(std::ptrdiff_t arg) noexcept;
原子性的加上参数值,返回计算后的值
T operator-=(T arg) noexcept;
T* operator-=(std::ptrdiff_t arg) noexcept;
原子性的减去参数值,返回计算后的值
T fetch_max(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_max(T* arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的将值设为当前值和传入参数间的较大值,并返回原值
T fetch_min(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_min(T* arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的将值设为当前值和传入参数间的较大值,并返回原值
T operator++() noexcept;
T* operator++(int)
T* operator++() noexcept;
T* operator++(int)
原子性的加1,返回计算后的值
T operator–() noexcept;
T* operator–(int)
T* operator–() noexcept;
T* operator–(int)
原子性的减1,返回计算后的值

只适用于整形的方法

接口 含义
T fetch_and(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_and(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的与参数值按位与,返回原值
T fetch_or(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_or(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的与参数值按位或,返回原值
T fetch_xor(T arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
T* fetch_xor(std::ptrdiff_t arg, std::memory_order order = std::memory_order_seq_cst) noexcept;
原子性的与参数值按位异或,返回原值
T operator&=(T arg) noexcept;
T* operator&=(std::ptrdiff_t arg) noexcept;
原子性的与参数值按位与,返回计算后的值
T operator =(T arg) noexcept;
T* operator
T operator^=(T arg) noexcept;
T* operator^=(std::ptrdiff_t arg) noexcept;
原子性的与参数值按位异或,返回计算后的值

atomic_flag

std::atomic_flag是原子布尔类型,其总是无锁的。

其提供如下方法:

接口 含义
bool test_and_set(std::memory_order order = std::memory_order_seq_cst) noexcept; 设置flag为true并返回原值
void clear(std::memory_order order = std::memory_order_seq_cst) noexcept; 设置flag为false

Bash未提供定时函数来设置程序终止时间,但可以通过后台运行+定时kill的方式实现相似功能,具体脚本Demo如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

./test &

PID=$!
# 也可以使用下述方法获取PID
# PID=`ps aux | grep './test' | grep -v 'grep' | awk '{print $2}'`

WAIT_TIME=5

sleep ${WAIT_TIME}

kill -9 ${PID}

wait ${PID}

下载GStreamer

使用Chocolatey安装GStreamer,使用管理员权限运行powershell,运行如下命令:

1
choco install -yes gstreamer gstreamer-devel gstreamer-mingw gstreamer-mingw-devel

下载安装VS2022

访问微软官网,下载安装器进行安装。

配置依赖

创建空项目,右键点击右侧解决方案下的项目名,在弹出的菜单中选择属性:

在属性页的C/C++ - 常规 - 附加包含目录中添加如下内容:

1
C:\gstreamer\1.0\mingw_x86_64\include\gstreamer-1.0;C:\gstreamer\1.0\mingw_x86_64\include\glib-2.0;C:\gstreamer\1.0\mingw_x86_64\include\libxml2;C:\gstreamer\1.0\mingw_x86_64\lib\glib-2.0\include;C:\gstreamer\1.0\msvc_x86_64\include\GL;C:\gstreamer\1.0\mingw_x86_64\include;

在属性页的连接器 - 常规 - 附加库目录中添加如下内容:

1
C:\gstreamer\1.0\msvc_x86_64\lib;C:\gstreamer\1.0\mingw_x86_64\lib;

在属性页的连接器 - 输出 - 附加依赖项中添加如下内容:

1
;gobject-2.0.lib;glib-2.0.lib;gstreamer-1.0.lib;

编写验证程序

根据GStreamer教程Demo,编写如下程序验证环境搭建情况。注意,在Windows环境下需要添加main_loop,否则无法打开视频播放窗口。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <gst/gst.h>

int main(int argc, char* argv[]) {
gst_init(&argc, &argv);

GstElement* pipeline = gst_parse_launch("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
GMainLoop* main_loop = g_main_loop_new(NULL, FALSE);

gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run(main_loop);

gst_element_set_state(pipeline, GST_STATE_NULL);

gst_object_unref(pipeline);
g_main_loop_unref(main_loop);
return 0;
}

运行后成功播放目标视频,证明环境搭建完毕。