一、下载源码
SDL官网
二、解压,拷贝android项目,并重新命名
2.1、解压
2.2,重命名项目名称(androidSDL)AndroidSDL Github
三、导入头文件和源文件,修改android.mk文件
3.1、在jni目录下创建SDL2文件夹,并拷贝相关头文件和源文件到该目录下
3.2、在jni/src目录下创建.cpp文件
main.cpp
#include "SDL.h"
int main(int,char**){return 0;
}
3.3、修改jni/src下的android.mk文件
Android.mk
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := mainSDL_PATH := ../SDL2LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include# Add your application source files here...
LOCAL_SRC_FILES := main.cppLOCAL_SHARED_LIBRARIES := SDL2LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -lOpenSLES -llog -landroidinclude $(BUILD_SHARED_LIBRARY)
四、使用NDK编译
4.1、环境变量path配置ndk路径
4.2、打开cmd命令窗口,进入到androidSDL/app/jni/目录,然后执行"ndk-build"命令进行编译
4.3、根目录下生成libs目录,里面会有对应的so库
五、依赖so库
5.1、创建新项目(AndroidSDLThread)Github
5.2、src/main创建jniLibs目录,拷贝so库
5.3、src/main/cpp下创建include文件夹,拷贝SDL头文件至此
5.4、CMakeList.txt文件下配置SDL头文件和库文件
cmake_minimum_required(VERSION 3.18.1)
project("androidsdlthread")#SDL统一路径
set(sdl_path ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
#添加SDL头文件
include_directories(${CMAKE_SOURCE_DIR}/include/SDL)
#添加SDL库
add_library(sdl SHARED IMPORTED)
set_target_properties(sdl PROPERTIES IMPORTED_LOCATION ${sdl_path}/libSDL2.so)add_library(sdl_shared SHARED IMPORTED)
set_target_properties(sdl_shared PROPERTIES IMPORTED_LOCATION ${sdl_path}/libc++_shared.so)add_library(sdl_main SHARED IMPORTED)
set_target_properties(sdl_main PROPERTIES IMPORTED_LOCATION ${sdl_path}/libmain.so)add_library(androidsdlthreadSHAREDnative-lib.cpp${CMAKE_SOURCE_DIR}/logger.h)
find_library(log-liblog)
target_link_libraries( # Specifies the target library.androidsdlthreadsdlsdl_sharedsdl_main-landroid${log-lib})
六、使用SDL信号量,实现等待通知机制
SDL(Simple DirectMedia Layer)库提供了信号量(semaphore)的支持,用于实现线程间的同步和通信。信号量是一种计数器,用于控制对共享资源的访问,可以实现多线程之间的同步和互斥,确保线程安全和资源的正确访问。
- 创建信号量:调用SDL_CreateSemaphore() 函数创建一个信号量对象。在底层,SDL库会调用操作系统提供的原生信号量创建函数,如sem_init()(Linux)或CreateSemaphore()(Windows)。
- 等待信号量:调用SDL_SemWait() 或类似的函数等待信号量。在底层,SDL库会调用操作系统提供的原生信号量等待函数,如sem_wait()(Linux)或WaitForSingleObject()(Windows)。如果信号量的计数值大于0,则将计数值减1,线程可以继续执行。如果计数值为0,则线程会被阻塞,直到有其他线程调用SDL_SemPost()增加了信号量的计数值。
- 发送通知:调用SDL_SemPost() 函数增加信号量的计数值。在底层,SDL库会调用操作系统提供的原生信号量增加函数,如sem_post()(Linux)或ReleaseSemaphore()(Windows)。增加计数值后,如果有线程正在等待该信号量,其中一个线程将被唤醒,可以继续执行。
- 销毁信号量:调用SDL_DestroySemaphore() 函数销毁信号量对象。在底层,SDL库会调用操作系统提供的原生信号量销毁函数,如sem_destroy()(Linux)或CloseHandle()(Windows)。
6.1、声明native方法
public native void startSDLThread();public native void postSDL();public native void releaseSDL();
6.2、生成jni函数
#include <jni.h>
#include <string>extern "C" {
#include <SDL_thread.h>
#include "logger.h"SDL_sem *g_sem = NULL;
int g_task_exit = 0;
int task1(void *data);
int task2(void *data);
int number=0;JNIEXPORT void JNICALL
Java_com_anniljing_androidsdlthread_MainActivity_startSDLThread(JNIEnv *env, jobject thiz) {g_task_exit=0;g_sem = SDL_CreateSemaphore(0);SDL_CreateThread(task1, "task1", NULL);SDL_CreateThread(task2, "task2", NULL);
}
JNIEXPORT void JNICALL
Java_com_anniljing_androidsdlthread_MainActivity_postSDL(JNIEnv *env, jobject thiz) {if (g_sem) {SDL_SemPost(g_sem);}
}JNIEXPORT void JNICALL
Java_com_anniljing_androidsdlthread_MainActivity_releaseSDL(JNIEnv *env, jobject thiz) {g_task_exit = 1;SDL_DestroySemaphore(g_sem);g_sem = NULL;
}
int task1(void *data) {while (!g_task_exit) {if (g_sem) {LOGD("task1 SemWait");SDL_SemWait(g_sem);number++;LOGD("task1 number:%d\n",number);}}return 0;
}
int task2(void *data) {while (!g_task_exit) {if (g_sem) {LOGD("task2 SemWait");SDL_SemWait(g_sem);number++;LOGD("task2 number:%d\n",number);}}return 0;
}
}
6.3、编译运行
我们需要把这个文件夹拷贝到自己的项目
- 启动了两个线程
- 虽然线程2被唤起的次数多一些,但是当线程1执行的时候,变量number也是同步的