Aprendizaje de subprocesos múltiples de C ++ 01 ciclo de vida del objeto y salida del subproceso y espera

hilo secundario:

void ThreadMain()
{
    
    
    cout << "begin sub thread main " << this_thread::get_id() << endl;
    for (int i = 0; i < 10; i++)
    {
    
    
        if (!is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
    cout << "end sub thread main " << this_thread::get_id() << endl;
}

Tres casos de función principal:
01:

int main(int argc, char* argv[])
{
    
    
{
    
    
thread th(ThreadMain);
}
getchar();
 return 0;
}

inserte la descripción de la imagen aquí

explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
    
    
        using _Tuple                 = tuple<decay_t<_Fn>, decay_t<_Args>...>;
        auto _Decay_copied           = _STD make_unique<_Tuple>(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
        constexpr auto _Invoker_proc = _Get_invoke<_Tuple>(make_index_sequence<1 + sizeof...(_Args)>{
    
    });

#pragma warning(push)
#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to
                                // extern C function under -EHc. Undefined behavior may occur
                                // if this function throws an exception. (/Wall)
        _Thr._Hnd =
            reinterpret_cast<void*>(_CSTD _beginthreadex(nullptr, 0, _Invoker_proc, _Decay_copied.get(), 0, &_Thr._Id));
#pragma warning(pop)

        if (_Thr._Hnd) {
    
     // ownership transferred to the thread
            (void) _Decay_copied.release();
        } else {
    
     // failed to start thread
            _Thr._Id = 0;
            _Throw_Cpp_error(_RESOURCE_UNAVAILABLE_TRY_AGAIN);
        }

Esto se debe a que cuando el puntero de función se usa como parámetro del constructor de subprocesos, se generará un identificador _Thr._Hnd. El ciclo de vida de este identificador es coherente con el del subproceso principal. Cuando finalice el subproceso principal, el identificador también será Debido a esto, cuando el subproceso secundario aún se está ejecutando, se producirá un error

02

int main(int argc, char* argv[])
{
    
    
{
    
    
thread th(ThreadMain);
th.detach(); }
  getchar();
 return 0;
}

Usar detach() para separar el subproceso secundario del subproceso principal es equivalente a convertir el subproceso secundario en un subproceso daemon y entregar el ciclo de vida de sus recursos, como identificadores, al subproceso secundario. Nota: el subproceso secundario no necesariamente se cierra después de que finaliza el subproceso principal, por lo que debe tener en cuenta que los subprocesos no utilizan la variable
java daemon thread :
un subproceso daemon se refiere a un subproceso que proporciona un servicio general en segundo plano cuando el programa se está ejecutando. no es una parte integral del programa.
La función de detach() es separar la asociación entre el subproceso y el subproceso principal, es decir, después de detach(), el subproceso continúa ejecutándose de forma independiente en segundo plano, y el subproceso principal ya no puede obtener el control del subhilo.La ejecución tampoco termina. Cuando finaliza el subproceso principal, la biblioteca de tiempo de ejecución es responsable de limpiar los recursos relacionados con el subproceso secundario.

Escenario de uso: quiero que el subproceso principal se ejecute junto con los subprocesos, pero no quiero mantener los objetos del subproceso especialmente
inserte la descripción de la imagen aquí

03

bool is_exit = false;
void ThreadMain()
{
    
    
    for (int i = 0; i < 10; i++)
    {
    
    
        if (is_exit) break;
        cout << "in thread " << i << endl;
        this_thread::sleep_for(chrono::seconds(1));//1000ms
    }
}
int main(int argc, char* argv[])
{
    
    
        thread th(ThreadMain);
        for (int i = 0; i < 10; i++)
        {
    
    
            if(i==5)
               th.join();
          
            this_thread::sleep_for(chrono::seconds(1));
            cout << "a   " << endl; 
        }
    return 0;
}

El método th.join() se usa para agregar el subproceso secundario al subproceso principal y otorgar el tiempo de ejecución de la CPU del subproceso principal al subproceso secundario. Por ejemplo, si se llama al método Join() del subproceso A en el subproceso B, el subproceso B no continuará ejecutándose hasta que el subproceso A termine de ejecutarse. Antes de unirse, la CPU asigna intervalos de tiempo a ambos subprocesos ( los subprocesos son la unidad básica de programación de la CPU ), y después de unirse, los subprocesos primero usan los intervalos de tiempo del subproceso principal original. Se llama en un lugar adecuado después de std::thread t(func), y su función es reciclar los recursos del subproceso creado correspondiente para evitar la fuga de recursos.
inserte la descripción de la imagen aquí

Se puede ver que en los primeros 5 segundos, el subproceso principal y el subproceso se imprimen alternativamente. A los 5 segundos, deje que el subproceso bloquee el subproceso principal, y el subproceso principal solo puede ejecutarse después de que el subproceso termine de ejecutarse. .
Si el hilo principal está escrito así:

 for (int i = 0; i < 10; i++)
        {
    
    
            if (i == 5)
                //th.join();
            is_exit = true; //通知子线程退出
            this_thread::sleep_for(chrono::seconds(1));
            cout << "a   " << endl; 
        }

Luego se informará un error, incluso si el subproceso parece haber terminado de ejecutarse, aún puede estar montado en la cola lista y otras operaciones no se consideran realmente como el final de la CPU, use th.join() para esperar para que finalice el subproceso, de lo contrario, su identificador Habrá problemas si el subproceso principal lo libera.
El motivo se puede ver en la documentación oficial:
Si se puede unir () entonces terminar (), de lo contrario no tendrá efectos. o errores de rendimiento (para unir) encontrados solo cuando se genera una excepción. Por lo tanto, el programador debe asegurarse de que el destructor nunca se ejecute mientras el subproceso aún se pueda unir. — nota final] la
función nunca se ejecuta

Supongo que te gusta

Origin blog.csdn.net/qq_42567607/article/details/125457433
Recomendado
Clasificación