ПроблемаСоединение или отсоединение объединенного или отсоединенного потока происходит в следующих случаях:
Панель Сведения о результате (Result Details) описывает, был ли поток ранее присоединен или отсоединен, а также показывает предыдущие связанные события.
Например, проблема возникает при соединении потока с thrd_join затем отсоединяется с помощью pthread_detach:
thrd_t id;
//...
thrd_join(id, NULL);
thrd_detach(id);
Обратите внимание, что поток считается соединенным только в том случае, если предыдущее соединение потоков выполнено успешно. Например, поток не считается соединенным в if ветвь здесь:
thrd_t t;
//...
if (thrd_success != thrd_join(t, 0)) {
/* Thread not considered joined */
}Анализ не может обнаружить случаи, когда объединенный поток отсоединяется, используя, например,
thrd_current() функция.
РискСтандарт C11 (пункты 7.26.5.3 и 7.26.5.6) гласит, что резьба не должна соединяться или отсоединяться после того, как она была ранее присоединена или отсоединена. Нарушение этих положений стандарта приводит к неопределенному поведению.
ЗафиксироватьИзбегайте присоединения потока, который уже был присоединен или отсоединен ранее. Аналогично, избегайте отсоединения потока, который уже был присоединен или отсоединен.
Пример - Соединение с последующим отсоединением резьбы
#include <stddef.h>
#include <threads.h>
#include <stdlib.h>
extern int thread_func(void *arg);
int main (void)
{
thrd_t t;
if (thrd_success != thrd_create (&t, thread_func, NULL)) {
/* Handle error */
return 0;
}
if (thrd_success != thrd_join (t, 0)) {
/* Handle error */
return 0;
}
if (thrd_success != thrd_detach (t)) {
/* Handle error */
return 0;
}
return 0;
}В этом примере использование thrd_detach на потоке, который ранее был соединен с thrd_join приводит к неопределенному поведению.
Во избежание ошибок компиляции в этом примере укажите стандарт C11 с опцией C standard version (-c-version).
Коррекция - избегайте отсоединения присоединенной резьбыУдалить thrd_join или thrd_detach заявление.
#include <stddef.h>
#include <threads.h>
#include <stdlib.h>
extern int thread_func(void *arg);
int main (void)
{
thrd_t t;
if (thrd_success != thrd_create (&t, thread_func, NULL)) {
/* Handle error */
return 0;
}
if (thrd_success != thrd_join (t, 0)) {
/* Handle error */
return 0;
}
return 0;
} Пример - Соединение потока, созданного в отключенном состоянии#include <stddef.h>
#include <pthread.h>
#define thread_success 0
extern void *thread_func(void *arg);
int main() {
pthread_t id;
pthread_attr_t attr;
if(thread_success != pthread_attr_init(&attr)) {
return 0;
}
if(thread_success != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
return 0;
}
if(thread_success != pthread_create(&id, &attr, thread_func, NULL)) {
return 0;
}
if(thread_success != pthread_join(id, NULL)) {
return 0;
}
return 0;
}В этом примере атрибуту потока присваивается состояние PTHREAD_CREATE_DETACHED. Поток, созданный с помощью этого атрибута, затем соединяется.
Коррекция - создание потоков как соединяемыхОдной из возможных корректировок является создание потока с атрибутом потока, назначенным состоянию PTHREAD_CREATE_JOINABLE а затем присоединить поток.
#include <stddef.h>
#include <pthread.h>
#define thread_success 0
extern void *thread_func(void *arg);
int main() {
pthread_t id;
pthread_attr_t attr;
if(thread_success != pthread_attr_init(&attr)) {
return 0;
}
if(thread_success != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)) {
return 0;
}
if(thread_success != pthread_create(&id, &attr, thread_func, NULL)) {
return 0;
}
if(thread_success != pthread_join(id, NULL)) {
return 0;
}
return 0;
}