TestPthread

Android NDK的pthread学习笔记

java多线程

在java用new Thread新建线程,cpp文件中的全局变量在所有线程中都是用同一个变量。函数是分开运行的。

new Thread(new Runnable() {
            public void run() {
                testPthread("Tom");
            }
        }).start();
        new Thread(new Runnable() {
            public void run() {
                testPthread("Mary");
            }
        }).start();

log

04-26 11:18:17.000 30848-30881/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=2
04-26 11:18:17.030 30848-30880/com.obarong.testpthread E/hello: I am hello in hello.cpp from Tom. num=2
04-26 11:18:18.700 30848-30881/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=3
04-26 11:18:18.730 30848-30880/com.obarong.testpthread E/hello: I am hello in hello.cpp from Tom. num=3
04-26 11:18:20.380 30848-30881/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=4
04-26 11:18:20.420 30848-30880/com.obarong.testpthread E/hello: I am hello in hello.cpp from Tom. num=4

native多线程

如果在C++里面开线程,会有错误

//        new Thread(new Runnable() {
//            public void run() {
                testPthread("Tom");
//            }
//        }).start();
//        new Thread(new Runnable() {
//            public void run() {
                testPthread("Mary");
//            }
//        }).start();

native-lib.cpp

void *printHello(void *args) {
    LOGE("enter printHello");
    LOGE("(char *)args=%s", (char *) args);

    char temp[100];
    strcpy(temp, (char *) args);
    sayhello(temp);

    // 释放线程资源
    pthread_attr_destroy(&pthreadAttr);
    pthread_exit(NULL); //!!!自动释放
}

extern "C"
JNIEXPORT void JNICALL
Java_com_obarong_testpthread_MainActivity_testPthread(JNIEnv *env, jobject instance, jstring str_) {
    const char *str = env->GetStringUTFChars(str_, 0);

    char temp[100];
    strcpy(temp, str);
    pthread_t pthread;

    pthread_attr_init(&pthreadAttr);  //初始化线程属性
    pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    int err = pthread_create(&pthread, &pthreadAttr, printHello, (void *) temp);
    if (err != 0)
        LOGE("can't create thread: %s\n", strerror(err));

//    sayhello(str);

    env->ReleaseStringUTFChars(str_, str);
}

log输出乱码

04-26 11:15:39.930 29620-29668/com.obarong.testpthread E/hello: I am hello in hello.cpp from ����TA. num=3
04-26 11:15:39.980 29620-29669/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=3
04-26 11:15:41.600 29620-29668/com.obarong.testpthread E/hello: I am hello in hello.cpp from ����TA. num=4
04-26 11:15:41.650 29620-29669/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=4
04-26 11:15:43.260 29620-29668/com.obarong.testpthread E/hello: I am hello in hello.cpp from ����TA. num=5
04-26 11:15:43.320 29620-29669/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=5

问题出在内存分配上,用malloc分配内存

char *temp = (char *) malloc(strlen(str) + 1);

log输出正常

04-27 19:54:44.750 30943-30975/com.obarong.testpthread E/hello: I am hello in hello.cpp from Tom. num=1
04-27 19:54:44.780 30943-30976/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=1
04-27 19:54:48.120 30943-30976/com.obarong.testpthread E/hello: I am hello in hello.cpp from Mary. num=2
04-27 19:54:48.130 30943-30975/com.obarong.testpthread E/hello: I am hello in hello.cpp from Tom. num=2

源代码

参考

NativeDemo:
Android NDK — Native 线程 pthread - 简书
https://www.jianshu.com/p/34d88df0cfe0

Android NDK — Java 与 C/C++ 的互相调用 - 简书
https://www.jianshu.com/p/cdfcfc7489bb

pthread_create_百度百科
https://baike.baidu.com/item/pthread_create

Android NDK 原生 API | Android NDK | Android Developers
https://developer.android.google.cn/ndk/guides/stable_apis

capturerunner.h 如下 #ifndef CAPTURERUNNER_H #define CAPTURERUNNER_H #include <thread> #include <atomic> #include "../common/XThreadPool.h" #include "../logger/logger.h" extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/fifo.h> } #define min_time_interval 40 struct CaptureRunnerParam { Capture* capt; // 视频捕获对象指针 AVFifo* fifo; // AVFifo帧数据队列 }; class CaptureRunner : public XTask { public: int Init(void* param); void Deinit(void); int Start(int time); int Stop(void); int Run(); private: std::atomic<bool> m_is_running; Logger::ptr m_logger; Capture* m_capt; AVFifo* m_fifo; int m_time_interval; }; #endif // CAPTURERUNNER_H capturerunner.cpp如下 #include "capturerunner.h" #include <chrono> using namespace std; int CaptureRunner::Init(void* param) { CaptureRunnerParam* c = (CaptureRunnerParam*)param; this->m_capt = c->capt; this->m_fifo = c->fifo; this->m_logger = DefaultLogger(); return 0; } void CaptureRunner::Deinit() { if(m_is_running) { this->Stop(); } return; } int CaptureRunner::Start(int time) { this->m_time_interval = time; Run(); return 0; } int CaptureRunner::Stop() { m_is_running = false; return 0; } int CaptureRunner::Run() { if(m_is_running) { m_logger->Error("Running now"); return -1; } m_is_running = true; int ret = 0; while(m_is_running) { AVFrame* frame = m_capt->CaptureFrame(); if(!frame) { m_logger->Error("readfile failed"); this_thread::sleep_for(chrono::seconds(1)); continue; } // 将帧写入AVFifo ret = av_fifo_write(m_fifo, &frame, 1); if(ret < 0) { m_logger->Error("write to fifo failed"); av_frame_free(&frame); continue; } if(m_time_interval > min_time_interval) { this_thread::sleep_for(chrono::milliseconds(m_time_interval)); } else { this_thread::sleep_for(chrono::milliseconds(min_time_interval)); } } return 0; } capt_test.cpp如下 #include <signal.h> #include <atomic> #include "../common/XThreadPool.h" #include "test.h" #include "../capt/capture.h" #include "../capt/capturerunner.h" extern "C" { #include <libavutil/fifo.h> #include <libavutil/imgutils.h> } using namespace std; Logger::ptr Logger2 = DefaultLogger(); class capt_write : public XTask { public: int Run(); void Stop(); int Init(CaptureRunnerParam* param); void Deinit(); atomic<bool> is_running; AVFifo* fifo; FILE* fp; AVPixelFormat pix_fmt; int width, height; }; int capt_write::Init(CaptureRunnerParam* par) { this->fifo = par->fifo; this->fp = fopen("/home/kylin/zxk/test20241029/output.yuv", "wb"); if(!fp) { Logger2->Error("Failed to open output file"); return -1; } // 从捕获对象获取参数 this->width = par->capt->m_width; this->height = par->capt->m_height; this->pix_fmt = par->capt->m_pixel_fmt; return 0; } int capt_write::Run() { if(is_running) { Logger2->Error("Running now"); return -1; } is_running = true; while(is_running) { if(av_fifo_can_read(fifo) <= 0) { Logger2->Warning("Fifo empty"); this_thread::sleep_for(chrono::seconds(1)); continue; } AVFrame* frame = nullptr; av_fifo_read(fifo, &frame, 1); if(!frame) { Logger2->Warning("frame is NULL"); continue; } // 计算各分量大小 size_t y_bytes = width * height; size_t u_bytes = 0, v_bytes = 0; switch(pix_fmt) { case AV_PIX_FMT_YUYV422: y_bytes = width * height * 2; // YUYV packed格式 break; case AV_PIX_FMT_YUV420P: u_bytes = width * height / 4; v_bytes = width * height / 4; break; case AV_PIX_FMT_BGR0: y_bytes = width * height * 4; // BGR0 packed格式 break; } // 写入文件 fwrite(frame->data[0], 1, y_bytes, fp); if(u_bytes > 0) fwrite(frame->data[1], 1, u_bytes, fp); if(v_bytes > 0) fwrite(frame->data[2], 1, v_bytes, fp); av_frame_free(&frame); } return 0; } void capt_write::Deinit() { if(is_running) { Stop(); } if(fp) { fclose(fp); } } void capt_write::Stop() { is_running = false; } bool stop2 = false; void sigint_handler02(int sig_num) { stop2 = true; } // 初始化V4L2捕获参数 void init_v4l2(CaptParam& c) { c.width = 1280; c.height = 720; c.file_name = "/dev/video0"; c.pixel_fmt = AV_PIX_FMT_YUYV422; c.v4l2_buffer_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; c.v4l2_memory_type = V4L2_MEMORY_MMAP; c.v4l2_pixel_fmt = V4L2_PIX_FMT_YUYV; } // 初始化文件捕获参数 void init_file(CaptParam& c) { c.file_name = "/home/kylin/zxk/test20241021/testyuv.yuv"; c.width = 1280; c.height = 720; c.pixel_fmt = AV_PIX_FMT_YUV420P; } // 初始化屏幕捕获参数 void init_screen(CaptParam& c) { c.width = 1920; c.height = 1080; c.pixel_fmt = AV_PIX_FMT_BGR0; } int capt_test() { CaptParam c; // 选择一种捕获方式初始化 (取消注释对应的行) //init_v4l2(c); // V4L2捕获 init_file(c); // 文件捕获 //init_screen(c); // 屏幕捕获 // 创建AVFifo AVFifo* fifo = av_fifo_alloc2(10 * 1024 * 1024, 1, 0); // 10MB缓冲区 // 创建捕获对象 (与上面选择的初始化方式对应) //Capture* capt = new V4L2Capture; Capture* capt = new FileCapture; //Capture* capt = new ScreenCapture; capt->Init(&c); // 设置任务参数 CaptureRunnerParam param; param.capt = capt; param.fifo = fifo; // 创建任务 auto c1 = make_shared<CaptureRunner>(); auto c2 = make_shared<capt_write>(); c1->Init(&param); c2->Init(&param); // 启动线程池 XThreadPool pool; pool.Init(2); pool.Start(); pool.AddTask(c1); pool.AddTask(c2); // 主循环 signal(SIGINT, sigint_handler02); signal(SIGKILL, sigint_handler02); while(!stop2) { this_thread::sleep_for(chrono::milliseconds(100)); } // 清理 c2->Deinit(); this_thread::sleep_for(chrono::milliseconds(1000)); c1->Deinit(); capt->Deinit(); av_fifo_freep2(&fifo); pool.Stop(); return 0; } CMakeLists.txt 如下 cmake_minimum_required(VERSION 3.15) project(CaptureTest) set(CMAKE_CXX_STANDARD 11) #添加头文件搜索路径 include_directories( ${CMAKE_SOURCE_DIR}/include /home/zhanghan/include /home/zhanghan/Log/Log-lib/include /usr/local/include ) #添加静态库路径 link_directories( /home/zhanghan/Log ) # 查找FFmpeg相关库 find_package(PkgConfig REQUIRED) pkg_check_modules(FFMPEG REQUIRED libavcodec libavformat libavutil libswscale libavdevice ) # 添加FFmpeg头文件 include_directories(${FFMPEG_INCLUDE_DIRS}) # 所有源文件 set(SOURCES main.cpp capt_test.cpp ../logger/logger.cpp ../logger/formatter.cpp ../logger/logsink.cpp ../logger/asynlopper.cpp ../capt/capturerunner.cpp ../capt/capture.cpp ../common/XThreadPool.cpp ../capt/ScreenCapture.cpp ../capt/V4L2Capture.cpp ../capt/FileCapture.cpp ) add_executable(capture_test ${SOURCES}) # 链接库 target_link_libraries(capture_test pthread ${FFMPEG_LIBRARIES} log ) 错误信息如下 zhanghan@zhanghan-virtual-machine:~/daima/2/test2/build$ make -- Configuring done -- Generating done -- Build files have been written to: /home/zhanghan/daima/2/test2/build Consolidate compiler generated dependencies of target capture_test [ 7%] Building CXX object CMakeFiles/capture_test.dir/capt_test.cpp.o In file included from /home/zhanghan/daima/2/test2/capt_test.cpp:6: /home/zhanghan/daima/2/test2/../capt/capturerunner.h:19:5: error: ‘AVFifo’ does not name a type 19 | AVFifo* fifo; // AVFifo帧数据队列 | ^~~~~~ /home/zhanghan/daima/2/test2/../capt/capturerunner.h:34:5: error: ‘AVFifo’ does not name a type 34 | AVFifo* m_fifo; | ^~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:25:5: error: ‘AVFifo’ does not name a type 25 | AVFifo* fifo; | ^~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp: In member function ‘int capt_write::Init(CaptureRunnerParam*)’: /home/zhanghan/daima/2/test2/capt_test.cpp:32:11: error: ‘class capt_write’ has no member named ‘fifo’ 32 | this->fifo = par->fifo; | ^~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:32:23: error: ‘struct CaptureRunnerParam’ has no member named ‘fifo’ 32 | this->fifo = par->fifo; | ^~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:40:30: error: ‘int Capture::m_width’ is protected within this context 40 | this->width = par->capt->m_width; | ^~~~~~~ In file included from /home/zhanghan/daima/2/test2/capt_test.cpp:5: /home/zhanghan/daima/2/test2/../capt/capture.h:87:9: note: declared protected here 87 | int m_width; | ^~~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:40:30: note: field ‘int Capture::m_width’ can be accessed via ‘int Capture::GetWidth() const’ 40 | this->width = par->capt->m_width; | ^~~~~~~ | GetWidth() /home/zhanghan/daima/2/test2/capt_test.cpp:41:31: error: ‘int Capture::m_height’ is protected within this context 41 | this->height = par->capt->m_height; | ^~~~~~~~ In file included from /home/zhanghan/daima/2/test2/capt_test.cpp:5: /home/zhanghan/daima/2/test2/../capt/capture.h:88:9: note: declared protected here 88 | int m_height; | ^~~~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:41:31: note: field ‘int Capture::m_height’ can be accessed via ‘int Capture::GetHeight() const’ 41 | this->height = par->capt->m_height; | ^~~~~~~~ | GetHeight() /home/zhanghan/daima/2/test2/capt_test.cpp:42:32: error: ‘AVPixelFormat Capture::m_pixel_fmt’ is protected within this context 42 | this->pix_fmt = par->capt->m_pixel_fmt; | ^~~~~~~~~~~ In file included from /home/zhanghan/daima/2/test2/capt_test.cpp:5: /home/zhanghan/daima/2/test2/../capt/capture.h:89:19: note: declared protected here 89 | AVPixelFormat m_pixel_fmt; | ^~~~~~~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:42:32: note: field ‘AVPixelFormat Capture::m_pixel_fmt’ can be accessed via ‘AVPixelFormat Capture::GetPixelFmt() const’ 42 | this->pix_fmt = par->capt->m_pixel_fmt; | ^~~~~~~~~~~ | GetPixelFmt() /home/zhanghan/daima/2/test2/capt_test.cpp: In member function ‘virtual int capt_write::Run()’: /home/zhanghan/daima/2/test2/capt_test.cpp:55:29: error: ‘fifo’ was not declared in this scope; did you mean ‘mkfifo’? 55 | if(av_fifo_can_read(fifo) <= 0) { | ^~~~ | mkfifo /home/zhanghan/daima/2/test2/capt_test.cpp:55:12: error: ‘av_fifo_can_read’ was not declared in this scope; did you mean ‘av_fifo_generic_read’? 55 | if(av_fifo_can_read(fifo) <= 0) { | ^~~~~~~~~~~~~~~~ | av_fifo_generic_read /home/zhanghan/daima/2/test2/capt_test.cpp:62:22: error: ‘fifo’ was not declared in this scope; did you mean ‘mkfifo’? 62 | av_fifo_read(fifo, &frame, 1); | ^~~~ | mkfifo /home/zhanghan/daima/2/test2/capt_test.cpp:62:9: error: ‘av_fifo_read’ was not declared in this scope; did you mean ‘avio_read’? 62 | av_fifo_read(fifo, &frame, 1); | ^~~~~~~~~~~~ | avio_read /home/zhanghan/daima/2/test2/capt_test.cpp: In function ‘int capt_test()’: /home/zhanghan/daima/2/test2/capt_test.cpp:149:5: error: ‘AVFifo’ was not declared in this scope 149 | AVFifo* fifo = av_fifo_alloc2(10 * 1024 * 1024, 1, 0); // 10MB缓冲区 | ^~~~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:149:13: error: ‘fifo’ was not declared in this scope; did you mean ‘mkfifo’? 149 | AVFifo* fifo = av_fifo_alloc2(10 * 1024 * 1024, 1, 0); // 10MB缓冲区 | ^~~~ | mkfifo /home/zhanghan/daima/2/test2/capt_test.cpp:149:20: error: ‘av_fifo_alloc2’ was not declared in this scope; did you mean ‘av_fifo_alloc’? 149 | AVFifo* fifo = av_fifo_alloc2(10 * 1024 * 1024, 1, 0); // 10MB缓冲区 | ^~~~~~~~~~~~~~ | av_fifo_alloc /home/zhanghan/daima/2/test2/capt_test.cpp:161:11: error: ‘struct CaptureRunnerParam’ has no member named ‘fifo’ 161 | param.fifo = fifo; | ^~~~ /home/zhanghan/daima/2/test2/capt_test.cpp:188:5: error: ‘av_fifo_freep2’ was not declared in this scope; did you mean ‘av_fifo_freep’? 188 | av_fifo_freep2(&fifo); | ^~~~~~~~~~~~~~ | av_fifo_freep 如何解决?
最新发布
06-06
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值