pergunta
Uma biblioteca de código aberto é usada no projeto, incluindo código C++ nativo, que possui muitas operações simultâneas, e a biblioteca <pthread.h> é usada para garantir a segurança do thread.
Entre eles, a sincronização de threads é realizada usando bloqueios de exclusão mútua. A situação normal do processo é:
- Inicialize o bloqueio – pthread_mutex_init
- Bloqueio – pthread_mutex_lock ou pthread_mutex_trylock
- desbloquear – pthread_mutex_unlock
- Bloqueio de destruição – pthread_mutex_destroy
No entanto, como a lógica é mais complicada, exceções de execução podem ocorrer ocasionalmente e os bloqueios são adicionados depois que o bloqueio é destruído.
Em seguida, haverá diferentes desempenhos em diferentes máquinas de teste, alguns podem ser executados normalmente, alguns estão travados e alguns até travam diretamente.
A/libc: FORTIFY: pthread_mutex_trylock called on a destroyed mutex (0xb511d6f8)
A/libc: Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 2775 (han.mynativeapp), pid 2775 (han.mynativeapp)
Analise os motivos
Para analisar a causa da exceção de sincronização de thread, use o seguinte código para simular a situação anormal:
#include <jni.h>
#include <string>
#include <malloc.h>
#include <pthread.h>
#include <android/log.h>
extern "C" JNIEXPORT jstring JNICALL
Java_com_shiyinghan_mynativeapp_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
pthread_mutex_t *mutex = static_cast<pthread_mutex_t *>(calloc(1, sizeof(*mutex)));
pthread_mutex_init(mutex, NULL);
pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);
pthread_mutex_destroy(mutex);
int r = pthread_mutex_trylock(mutex);
__android_log_print(ANDROID_LOG_INFO,"stringFromJNI","pthread_mutex_trylock %p %d", mutex, r);
return env->NewStringUTF(hello.c_str());
}
Em seguida, os resultados da execução usando diferentes versões do Android são:
versão do Android | logcat | Resultados do |
---|---|---|
6.0 | I/stringFromJNI: pthread_mutex_trylock 0x557ef45d20 0 | bloqueio com sucesso |
8.1 | I/stringFromJNI: pthread_mutex_trylock 0x557f13cc30 16 | bloqueio falhou |
10 | A/libc: FORTIFY: pthread_mutex_trylock chamado em um mutex destruído (0xb511d6f8) | O aplicativo falha |
11 | A/libc: FORTIFY: pthread_mutex_trylock chamado em um mutex destruído (0xb511d6f8) | O aplicativo falha |
Embora apenas quatro versões tenham sido selecionadas, não testei mais versões e não usei para comparar marcas diferentes. Testei apenas o emulador e duas marcas de celulares, mas pode-se observar que conforme a versão do Android aumenta , <pthread.h> biblioteca, a imposição de pthread mutex está ficando mais rigorosa . Depois que pthread_mutex_destroy destrói o bloqueio, a versão inferior ainda pode bloquear com êxito, a versão ligeiramente superior falhará ao bloquear e a versão mais recente causa diretamente a falha do aplicativo.
Teste no Linux
A camada inferior do Android é o kernel do Linux. O que acontecerá se ele for executado diretamente no Linux? O código é o seguinte:
#include <stdio.h>
#include <malloc.h>
#include <pthread.h>
int main() {
pthread_mutex_t *mutex = calloc(1, sizeof(*mutex));
pthread_mutex_init(mutex, NULL);
pthread_mutex_lock(mutex);
pthread_mutex_unlock(mutex);
pthread_mutex_destroy(mutex);
int r = pthread_mutex_trylock(mutex);
printf("pthread_mutex_trylock %p %d\n", mutex, r);
return 0;
}
O resultado da execução é:
versão Linux | logcat | Resultados do |
---|---|---|
centos 7.9 Linux versão 3.10.0 | pthread_mutex_trylock 0xf31010 22 | bloqueio falhou |
Ubuntu 20.04.3 Linux versão 5.11.0 | pthread_mutex_trylock 0x556bcaa062a0 22 | bloqueio falhou |
Pode-se observar que, embora a versão do Linux seja diferente, o resultado é que o bloqueio falha , mas não ocorre nenhum erro de execução.
Resumir
Ao comparar os resultados do teste de bloqueio anormal mutex, pode-se ver que a biblioteca <pthread.h> na parte inferior do Android tem sua própria implementação exclusiva, que é inconsistente com outras distribuições do Linux, e quanto maior a versão do Android, o < pthread.h> Bibliotecas com imposição mais rigorosa podem travar o aplicativo imediatamente.
Portanto, para garantir a máxima compatibilidade e robustez do programa NDK, no processo de uso da biblioteca <pthread.h> para realizar a sincronização de threads, é necessário garantir que a aplicação do mutex siga o processo normal de uso para evitar ocorrências semelhantes ao mutex sendo bloqueado. O caso de re-bloqueio após a destruição.