如果我们的code 没有及时git commit,如果你还幸运的话,使用了 git add 命令,可以使用:
git fsck --lost-found
命令找回,然后在 .git/lost-found/other 目录下有一些 commit的id。可以grep下然后重命名得到 想找的那个文件。
注意: 必须在git add命令的前提下,如果这一步你都没做,哈哈哈哈。
现在开始介入thread的初步知识。
直接上一个demo code:
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
// 綫程運行的函數
void* say_hello(void* args){
cout << "Hello, vimer" << endl;
return 0;
}
int main(){
// 定义线程的ID变量,多个变量使用数组
pthread_t tids[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++){
// 参数依次是: 创建线程的id, 线程参数, 调用的函数,传入的函数args
int ret = pthread_create(&tids[i], NULL, say_hello, NULL);
if(ret != 0)
cout << "pthread_create error: error_code=" << ret << endl;
}
// 等各个线程退出后,进程才结束,否则进程强制结束了,线程可能还没有反应过来
pthread_exit(NULL);
}
编译命令:
g++ thread.cpp -lpthread -o test
其实,这里有意思的是,不同时间执行的输出是不一样的:
vimer@user-HP:~/test/thread$ ./test
Hello, vimer
Hello, vimerHello, vimer
Hello, vimer
Hello, vimer
vimer@user-HP:~/test/thread$ ./test
Hello, vimer
Hello, vimer
Hello, vimer
Hello, vimer
Hello, vimer
是这样的,目前还是有点难以理解。 看一下具体的api吧:
/* Create a new thread, starting with execution of START-ROUTINE
getting passed ARG. Creation attributed come from ATTR. The new
handle is stored in *NEWTHREAD. */
extern int pthread_create (pthread_t *__restrict __newthread,
const pthread_attr_t *__restrict __attr,
void *(*__start_routine) (void *),
void *__restrict __arg) __THROWNL __nonnull ((1, 3));
/* Terminate calling thread.
The registered cleanup handlers are called via exception handling
so we cannot mark this function with __THROW.*/
extern void pthread_exit (void *__retval) __attribute__ ((__noreturn__));
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void *PrintHello(void *threadid){
// 对传入的参数进行强制类型转换,由无类型指针转化为整型指针
int tid = *((int*)threadid);
cout << "Hello vimer! thread id" << tid << endl;
pthread_exit(NULL);
}
int main()
{
pthread_t threads[NUM_THREADS];
int indexes[NUM_THREADS];
int rc;
int i;
for(i = 0; i < NUM_THREADS; i++){
cout << "main(): create thread," << i << endl;
indexes[i] = i; // 保存i的值
// 传入的时候必须强制转换为void *类型,即无类型指针
rc = pthread_create(&threads[i], NULL, PrintHello,
(void*)&(indexes[i]));
if (rc){
cout << "fail to create thread" << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
输出的结果如下:
vimer@user-HP:~/test$ ./test
main(): create thread,0
main(): create thread,1
Hello vimer! thread id0
main(): create thread,2
Hello vimer! thread id1
main(): create thread,3
Hello vimer! thread id2
Hello vimer! thread id3
main(): create thread,4
Hello vimer! thread id4
下面这个例子是传递结构体参数:
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
struct thread_data{
int thread_id;
char *message;
};
void *PrintHello(void *threadargs){
struct thread_data *my_data;
my_data = (struct thread_data *)threadargs;
cout << "Thread ID: " << my_data->thread_id;
cout << " Message:" << my_data->message << endl;
pthread_exit(NULL);
}
int main()
{
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc, i;
for ( i = 0; i < NUM_THREADS; i++){
cout << "main(): create thread" << i << endl;
td[i].thread_id = i;
td[i].message = (char *)"this is message";
rc = pthread_create(&threads[i], NULL,
PrintHello, (void *)&td[i]);
if (rc) {
cout << "fail to create thread" << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
输出log :
vimer@user-HP:~/test$ ./test
main(): create thread0
main(): create thread1
Thread ID: 0 Message:this is message
main(): create thread2
Thread ID: 1 Message:this is message
main(): create thread3
Thread ID: 2 Message:this is message
Thread ID: 3 Message:this is message
main(): create thread4
Thread ID: 4 Message:this is message
cnblog的一系列文章写得非常不错,他是一个系列的。 链接中是动态创建Pipeline.
为了更直观的展现element,我们通常用一个框来表示一个element,在element内部使用小框表示pad。
source element: 只能生成数据的,不能接收数据的, 如 filesrc
sink element: 只能接收数据,不能产生数据的
Fliter-like element: 过滤数据,对数据进行处理
Pad是一个element的输入输出接口,有src pad(producting data),sink pad(consuming data)这两种类型的接口。两个element必须通过pad才能连接起来,且pad有当前element所能处理的数据类型(capabilities),需要在连接时通过比较 src pad和sink pad中所支持的能力,来选择最恰当、或者用户指定的某种数据类型进行传输。
video/x-raw,format=RGB,width=300,height=200,framerate=30/1
就是一个pad的样例。
作用: 1、 协商阶段选择相同的数据类型 2、数据,消息传输
使用gstreamer工具来查看element所支持的capabilities(gst-inspect-1.0 v4l2src)
一个例子:
...
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
image/jpeg
video/mpeg
mpegversion: 4
systemstream: false
video/mpeg
mpegversion: 2
video/mpegts
systemstream: true
video/x-bayer
format: { (string)bggr, (string)gbrg, (string)grbg, (string)rggb }
width: [ 1, 32768 ]
height: [ 1, 32768 ]
framerate: [ 0/1, 2147483647/1 ]
video/x-dv
systemstream: true
video/x-h263
variant: itu
video/x-h264
stream-format: { (string)byte-stream, (string)avc }
alignment: au
video/x-pwc1
width: [ 1, 32768 ]
height: [ 1, 32768 ]
framerate: [ 0/1, 2147483647/1 ]
video/x-pwc2
width: [ 1, 32768 ]
height: [ 1, 32768 ]
framerate: [ 0/1, 2147483647/1 ]
video/x-raw
format: { (string)RGB16, (string)BGR, (string)RGB, (string)GRAY8, (string)GRAY16_LE, (string)GRAY16_BE, (string)YVU9, (string)YV12, (string)YUY2, (string)YVYU, (string)UYVY, (string)Y42B, (string)Y41B, (string)YUV9, (string)NV12_64Z32, (string)NV24, (string)NV61, (string)NV16, (string)NV21, (string)NV12, (string)I420, (string)BGRA, (string)BGRx, (string)ARGB, (string)xRGB, (string)BGR15, (string)RGB15 }
width: [ 1, 32768 ]
height: [ 1, 32768 ]
framerate: [ 0/1, 2147483647/1 ]
video/x-sonix
width: [ 1, 32768 ]
height: [ 1, 32768 ]
framerate: [ 0/1, 2147483647/1 ]
always: 一直存在;
Sometimes: 在某些特定场景中才会存在;
On request: tee元件
举例:
Pad Templates:
SINK template: 'sink'
Availability: Always
Capabilities:
ANY
SRC template: 'src_%u'
Availability: On request
Capabilities:
ANY
tee的SINK pad是Always,也就是说他需要接收上端的src 文件,但是出去几路,需要根据用户的请求来设定。
bin是一个特殊的element,其实包含了几个其他的子elements,类似函数的概念。好处是简化Pipeline
描述某一element可以接收后者产生的所有媒体类型的集合,是由一组GstStrcut和GstStruct的GstCapsFeatures(可选)组成。
GstStruct: a collection of key/value pairs.
通过GstCapsImpl这个结构体完成的。
使用 gst-inspect-1.0查找不同elements的允许值。
设置属性方式: g_object_set(v4l2src, “device”, “/dev/video1”, NULL)
得到属性方式: g_object_get(volume, “volume”, &level, NULL)
gst-inspect-1.0 appsrc
Element Signals:
"need-data" : void user_function (GstElement* object,
guint arg0,
gpointer user_data);
"enough-data" : void user_function (GstElement* object,
gpointer user_data);
"seek-data" : gboolean user_function (GstElement* object,
guint64 arg0,
gpointer user_data);
Element Signals: 插件在运行过程中满足某种条件可以发出的signal.以appsrc为例: 如果设置emit-signals为true,那么在appsrc运行过程中满足某种条件就可以发出singal。 该singal可以调用用户自己定义的函数。
Element action: 在插件中规定了用户触发某种信号所引起的行为。
可以看做是一些描述:
vimer@user-HP:~$ gst-inspect-1.0 appsrc
Factory Details:
Rank none (0)
Long-name AppSrc
Klass Generic/Source
Description Allow the application to feed buffers to a pipeline
Author David Schleef <[email protected]>, Wim Taymans <[email protected]>
code
void
gst_element_class_set_metadata (GstElementClass * klass,
const gchar * longname, const gchar * classification,
const gchar * description, const gchar * author)
{
g_return_if_fail (GST_IS_ELEMENT_CLASS (klass));
g_return_if_fail (longname != NULL && *longname != '\0');
g_return_if_fail (classification != NULL && *classification != '\0');
g_return_if_fail (description != NULL && *description != '\0');
g_return_if_fail (author != NULL && *author != '\0');
gst_structure_id_set ((GstStructure *) klass->metadata,
GST_QUARK (ELEMENT_METADATA_LONGNAME), G_TYPE_STRING, longname,
GST_QUARK (ELEMENT_METADATA_KLASS), G_TYPE_STRING, classification,
GST_QUARK (ELEMENT_METADATA_DESCRIPTION), G_TYPE_STRING, description,
GST_QUARK (ELEMENT_METADATA_AUTHOR), G_TYPE_STRING, author, NULL);
}
通过GST_PLUGIN_DEFINE来定义。
GstPipeline->GstBin->GstElement
struct _GstPipeline {
GstBin bin;
/*< public >*/ /* with LOCK */
GstClock *fixed_clock;
GstClockTime stream_time;
GstClockTime delay;
/*< private >*/
GstPipelinePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
摘自: gstreamer/gstreamer-1.14.5/gst/gstpipeline.h
构建pipeline的方式:
gst-launch-1.0 videotestsrc ! "video/x-raw,width=1920,height=1080,framerate=60/1" ! videoscale ! "video/x-raw,width=720,height=480" ! videoflip method=5 ! xvimagesink
不同的元件由”!”隔开。
gst_parse_launch(“fakesrc ! fakesink”, NULL)
如以下命令:
vimer@user-HP:~/ms/edk_test$ gst-launch-1.0 v4l2src device=/dev/video1 ! video/x-raw,format=YUY2,width=640,height=480 ! tee name=t ! queue ! xvimagesink t. ! queue ! fakesink
我们注意到tee,这里会创建2路pipeline,由于上不了图片,注意t.
那里。
tee->queue->xvimagesink
|
> queue -> fakesink
gst-inspect-1.0 tee
SRC template: 'src_%u'
Availability: On request
Capabilities:
ANY
# src_%u %就是接的用户自己创建的src pad的个数.
某些情况下,我们希望自己指定某个pad用于连接,我们可以指定自己命名的Element 的pad来实现,或者某些元件必须指定pad才能正常连接。
gst-launch-1.0 v4l2src device=/dev/vide01 ! video/x-raw,format=YUY2,width=640,height=480 ! tee name=t t.src_00 ! queue ! xvimagesink t.src_01 ! queue ! fakesink
这样就指定了具体的pipeline分支。
gsteamer提供了可以给用户程序进行交互的方式, appsrc和appsink
appsrc: 用于将应用程序的数据发送到pipeline中,应用程序负责数据的生成,并将其作为 GstBuffer
传输到Pipeline中去。
appsink: 用于从Pipeline中提取数据,并发送到应用程序中去。
GstBuffer: 在GStreamer Pipeline中的plugin间传输的数据块成为buffer,在GStreamer内部成为GstBuffer。Buffer由Source Pad生成,并由Sink Pad消耗。
nvv4l2camerasrc ->(UYUV(nv memory))-> nvvidconv -> (I420 cpu memory)->appsink
另一个case vedio display:
appsrc->(I420 cpu memory)->nvvidconv->(I420 nv memory)->nv3dsink
有两种: downstream(Dataflow and event) 和 upstream(event)
NULL(初始状态)-> READY (准备接受数据)-> PAUSED(Pad active status) -> PLAYING(processing data)
gst-discoverer-1.0: 查看音视频文件的详细数据。
gst-play-1.0: 播放文件
gst-device-monitor: gst-device-monitor Audio/Source
创建Pipeline的element的关系图:
GST_DEBUG_DUMP_DOT_DIR=.
gst-launch-1.0 videotestsrc ! "video/x-raw,width=1920,height=1080,framerate=60/1" ! videoscale ! "video/x-raw,width=720,height=480" ! videoflip method=5 ! xvimagesink
# sudo apt install graphviz
dot -T png pipeline.png xx.dot
先看一下这篇文章,后面再把自己在开发过程中遇到的记录下来。 这一篇csdn看着效果也挺好的。 真正的东西还得看官方文档
it would be much better to directly fetch the installation information from GCC,
i.e.
gcc -print-search-dirs
gcc -print-multiarch
目前中文的资料介绍diagnostic的介绍资料较少一些,故积累本文以作总结。
Makefile 如下
CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
puts.c如下:
#include <stdio.h>
int main(int argc, const char *argv[])
{
while(*++argv)
puts(*argv);
return 0;
}
编译的时候,error显示如下:
vimer@user-HP:~/test/gcc$ make
cc -std=c11 -W -Wall -pedantic -Werror puts.c -o puts
puts.c: In function ‘main’:
puts.c:12:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
int main(int argc, const char *argv[])
^~~~
cc1: all warnings being treated as errors
<builtin>: recipe for target 'puts' failed
make: *** [puts] Error 1
之所以有这些error,需要注意到cppflags
的那几个字段,是这几个决定了编译的具体行为。
当然,gcc编译的常用选项也需要进行一番总结。
int main(__attribute__((unused)) int argc, const char *argv[])
{
while(*++argv)
puts(*argv);
return 0;
}
编译结果:
vimer@user-HP:~/test/gcc$ make
cc -std=c11 -W -Wall -pedantic -Werror puts.c -o puts
__attribute__
是GCC的扩展,当然也是来自LLVM的支持。如果想写出可移植的代码,需要将该字段放到宏中去编写。
这个后面我们再总结一下。
这个代码没有编译成功:
#include <unistd.h>
_Pragam("GCC diagnostic push")
_Pragam("GCC diagnostic ignore \"-Wunused-parameter\"")
int main(__attribute__((unused)) int argc, const char *argv[])
{
while(*++argv)
puts(*argv);
return 0;
}
_Pragam("GCC diagnostic pop")
编译的log如下,但是这篇文章的主旨不是这里,所以暂且不表。
vimer@user-HP:~/test/gcc$ make
cc -std=c11 -W -Wall -pedantic -Werror puts.c -o puts
puts.c:11:9: error: expected declaration specifiers or ‘...’ before string constant
_Pragam("GCC diagnostic push")
^~~~~~~~~~~~~~~~~~~~~
puts.c:21:9: error: expected declaration specifiers or ‘...’ before string constant
_Pragam("GCC diagnostic pop")
^~~~~~~~~~~~~~~~~~~~
<builtin>: recipe for target 'puts' failed
make: *** [puts] Error 1
先看代码
#include <stdio.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
int main(__attribute__((unused)) int argc, const char *argv[])
{
while(*++argv)
puts(*argv);
return 0;
}
#pragma GCC diagnostic pop
编译的log如下:
vimer@user-HP:~/test/gcc$ make
cc -std=c11 -W -Wall -pedantic -Werror puts.c -o puts
怎么样,出乎意料吧,其实这里才是这篇文章的主题: c源码程序中借助这样的技巧,把一些不可避免的 warning给屏蔽掉。看一下我们的工程代码:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#include <gst/video/videooverlay.h>
#pragma GCC diagnostic pop
这里难道是 include 的文件有问题? -Wconversion
大概率设涉及到类型的转换之类的。而且,这个声明必须放到
.c
文件中去做。
最后是修改Makefile,实际效果我没有进行试验,但是我估计应该是可以的。
CPPFLAGS:=-std=c11 -W -Wall -pedantic -Werror
.PHONY: all
all: puts
puts.o: CPPFLAGS+=-Wno-unused-parameter
具体的code 参考
这个用法是有具体语法的,比如
#pragma GCC diagnostic kind option
以下摘自官方:
Modifies the disposition of a diagnostic. Note that not all diagnostics are modifiable; at the moment only warnings (normally controlled by ‘-W…’) can be controlled, and not all of them. Use -fdiagnostics-show-option to determine which diagnostics are controllable and which option controls them.
kind is ‘error’ to treat this diagnostic as an error, ‘warning’ to treat it like a warning (even if -Werror is in effect), or ‘ignored’ if the diagnostic is to be ignored. option is a double quoted string that matches the command-line option.
#pragma GCC diagnostic warning "-Wformat"
#pragma GCC diagnostic error "-Wformat"
#pragma GCC diagnostic ignored "-Wformat"
Note that these pragmas override any command-line options. GCC keeps track of the location of each pragma, and issues diagnostics according to the state as of that point in the source file. Thus, pragmas occurring after a line do not affect diagnostics caused by that line.
说的很明白,就是 #pragma
会覆盖编译选项的(比如来自makefile什么的),所以引入了下面的技巧:
#pragma GCC diagnostic push
#pragma GCC diagnostic pop
我们的声卡使用的,如下:
lsusb
:
user@linux:/proc$ lsusb
Bus 002 Device 003: ID 0424:5744 Standard Microsystems Corp.
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 016: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Bus 001 Device 014: ID 03f0:094a Hewlett-Packard Optical Mouse [672662-001]
Bus 001 Device 012: ID 08bb:29c3 Texas Instruments PCM2903C Audio CODEC
Bus 001 Device 011: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 017: ID 0424:2740 Standard Microsystems Corp.
Bus 001 Device 015: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 020: ID 1c4f:0002 SiGma Micro Keyboard TRACER Gamma Ivory
Bus 001 Device 010: ID 0424:2744 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
cat一下/proc的内容:
user@linux:/proc$ cat asound/cards
0 [tegrahdaxnx ]: tegra-hda-xnx - tegra-hda-xnx
tegra-hda-xnx at 0x3518000 irq 64
1 [jetsonxaviernxa]: jetson-xaviernx - jetson-xaviernx-ape
jetson-xaviernx-ape
2 [CODEC ]: USB-Audio - USB AUDIO CODEC
BurrBrown from Texas Instruments USB AUDIO CODEC at usb-3610000.xhci-3.1, full
也就是IT的xhci USB芯片,这说明,声卡的驱动是没有问题的, 但是pactl list cards
却是找不到,由于该命令输出过于
verbose,所以暂时不贴出来了。我们通过资料分析得知,pulse的默认配置文件在/etc/pulse/default.pa
,我们已经指定了
pulse使用 IT的这个USB作为输入:
cat /etc/pulse/default.pa
### Modules to allow autoloading of filters (such as echo cancellation)
### on demand. module-filter-heuristics tries to determine what filters
### make sense, and module-filter-apply does the heavy-lifting of
### loading modules and rerouting streams.
load-module module-filter-heuristics
load-module module-filter-apply
### Make some devices default
set-default-sink alsa_output.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo
set-default-source alsa_input.usb-BurrBrown_from_Texas_Instruments_USB_AUDIO_CODEC-00.analog-stereo
还有一个tip是,其实pulseaudio还有一个damon的配置文件: /etc/pulase/daemon.conf,这个文件可以再次指定 pulse的配置文件。
现象就是: 声卡驱动可以找到,但是pulseaudio播放异常,另外,使用 aplay -D plughw:D(card number) test.wav
也可以正常播放。或者使用 pulseaudio -k
也可以enable pulseaudio 工作。
我们一个直觉是: 有人改了pulseaudio的配置文件,导致目前的配置文件不生效了。其实,这个直觉也很重要,这是debug 的一个重要能力。
之前没有使用到这个命令,确实有点陌生。我使用 pstree -p
看一下:
user@linux:~$ pstree -p | grep pulse
|-pulseaudio(7914)-+-{pulseaudio}(8021)
| |-{pulseaudio}(8128)
| |-{pulseaudio}(8155)
| |-{pulseaudio}(8213)
| `-{pulseaudio}(8268)
|-pulseaudio(8132)-+-{pulseaudio}(8237)
| |-{pulseaudio}(8252)
| |-{pulseaudio}(8524)
| |-{pulseaudio}(8530)
| `-{pulseaudio}(8602)
看,这里有两个pid,直觉觉得,系统有一个pulseaudio的daemon进程就够了,那为啥有两个?如果有两个,看看是哪两个呗。
说实话,之前对systemd是有一些误解的。在这种情况下,想知道7914和8132是谁call起来的,systemctl就可以找到。
ystemctl status PID
user@linux:~$ systemctl status 7914
● ems.service - e-Media service
Loaded: loaded (/lib/systemd/system/ems.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2021-12-22 13:35:35 CST; 3h 23min ago
Process: 7333 ExecStart=/bin/bash -c USERNAME=$(cat /etc/passwd | grep home | grep 1000 | cut -d: -f1); sudo -u $USERNAME /usr/bin/eswin/ems; (code=exited, status=0/SUCCESS)
Main PID: 7370 (ems)
Tasks: 30 (limit: 4915)
CGroup: /system.slice/ems.service
├─7370 /usr/bin/eswin/ems
├─7706 dbus-launch --autolaunch a3d9197b765643568af09eb2bd3e5ce7 --binary-syntax --close-stderr
├─7728 /usr/bin/dbus-daemon --syslog-only --fork --print-pid 5 --print-address 7 --session
├─7738 /usr/lib/at-spi2-core/at-spi-bus-launcher
├─7760 /usr/lib/gvfs/gvfsd
├─7796 /usr/lib/gvfs/gvfsd-fuse /home/user/.gvfs -f -o big_writes
├─7808 /usr/bin/dbus-daemon --config-file=/usr/share/defaults/at-spi2/accessibility.conf --nofork --print-address 3
├─7859 /usr/lib/at-spi2-core/at-spi2-registryd --use-gnome-session
└─7914 /usr/bin/pulseaudio --start --log-target=syslog
另一个pid:
user@linux:~$ systemctl status 8132
● session-c5.scope - Session c5 of user user
Loaded: loaded (/run/systemd/transient/session-c5.scope; transient)
Transient: yes
Active: active (running) since Wed 2021-12-22 13:35:32 CST; 3h 24min ago
Tasks: 66
CGroup: /user.slice/user-1000.slice/session-c5.scope
├─6895 lightdm --session-child 12 15
├─6967 /usr/bin/lxsession -s LXDE -e LXDE
├─8005 /usr/bin/ssh-agent /usr/bin/im-launch env LD_PRELOAD=libgtk3-nocsd.so.0 /usr/bin/startlxde
├─8024 /usr/bin/fcitx
├─8034 /usr/bin/dbus-daemon --syslog --fork --print-pid 5 --print-address 7 --config-file /usr/share/fcitx/dbus/daemon.conf
├─8038 /usr/bin/fcitx-dbus-watcher unix:abstract=/tmp/dbus-IweAOwOXgr,guid=5fc05ee218ca40a14535b89a61c2b929 8034
├─8060 openbox --config-file /home/user/.config/openbox/lxde-rc.xml
├─8062 lxpolkit
├─8065 lxpanel --profile LXDE
├─8067 pcmanfm --desktop --profile LXDE
├─8068 xscreensaver -no-splash
├─8071 compton --backend glx -b
├─8075 /usr/bin/ssh-agent -s
├─8082 /usr/lib/deja-dup/deja-dup-monitor
├─8097 update-notifier
├─8101 nm-applet
├─8103 python3 /usr/share/nvpmodel_indicator/nvpmodel_indicator.py
├─8105 zeitgeist-datahub
├─8132 /usr/bin/pulseaudio --start --log-target=syslog
显而易见,8132是系统级别的,一般的情况下,我们无法触动他的启动,7914是我们开发的ems引发的,大概率问题出现在这里面。
经过询问相关的同事,确实在代码里调用了pulseaudio
.
其实,这个过程更像是debug的一个回顾: