ПроблемаСоединение или отсоединение объединенного или отсоединенного потока происходит в следующих случаях:
Поток, который соединяется, был ранее соединен или отсоединен
Резьба, которая отсоединена, была предварительно соединена или отсоединена.
Панель 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. Затем создается поток, созданный с использованием этого атрибута.
Коррекция - Создавайте потоки как JoinableОдной из возможных коррекций является создание потока с атрибутом потока, назначенным состоянию 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;
}