Está en la página 1de 34

UNIVERSIDAD NACIONAL DE SAN AGUSTIN

FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS


ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 1

INFORME DE LABORATORIO

INFORMACIÓN BÁSICA
ASIGNATURA: Laboratorio de Sistemas Operativos - C
TÍTULO DE LA
Introducción a Linux
PRÁCTICA:
NÚMERO DE NRO.
04 AÑO LECTIVO: 2023 VI
PRÁCTICA: SEMESTRE:
FECHA DE HORA DE
08/06/2023
PRESENTACIÓN PRESENTACION
ALUMNO:
Llaique Chullunquia Angie Carolina NOTA:

DOCENTE(s):
Apaza Aceituno Roni Guillermo

SOLUCIÓN Y RESULTADOS
I. EJERCICIOS RESUELTOS POR EL DOCENTE

Ejercicio 1.
Implementar el siguiente código en c++ y guardarlo en un archivo código01.cpp:
// ejemplo de variable de condición
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id (int id) {
std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}
void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 2

cv.notify_all();
}
int main ()
{
std::thread threads[10];
// aparecen 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_id,i);
std::cout << "10 threads listos para la carrera...\n";
go(); // vamos
for (auto& th : threads) th.join();
return 0;
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio01.cpp -o ejercicio01 -std=c++17 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 3

Ejercicio 2.
Implementar el siguiente código en c++ y guardarlo en un archivo código02.cpp:
#include <condition_variable>
#include <cstddef>
#include <iostream>
#include <mutex>
#include <queue>
#include <random>
#include <thread>
int main()
{
std::condition_variable cond;
std::mutex mtx;
std::queue<int> intq;
bool stopped = false;
std::thread producer{[&]()
{
// Preparar un generador de numeros aleatorios.
// El productor ingresa numeros aleatorios a intq.
//
std::default_random_engine gen{};
std::uniform_int_distribution<int> dist{};
std::size_t count = 4006;
while(count--)
{
// Siempre bloquea antes de cambiar
// El estado es guardado por un mutex y
// también afecta a la variable de condición (cond).
std::lock_guard<std::mutex> L{mtx};
// Ingresa un entero aleatorio dentro de la cola
intq.push(dist(gen));
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 4

// Habla al consumidor que tiene un entero


cond.notify_one();
}
// Todo hecho.
// Adquiere la cerradura, establece la bandera detenida,
// entonces informa al consumidor.
std::lock_guard<std::mutex> L{mtx};
std::cout << "Productor esta hecho!" << std::endl;
stopped = true;
cond.notify_one();
}};
std::thread consumer{[&]()
{
do{
std::unique_lock<std::mutex> L{mtx};
cond.wait(L,[&]()
{
// Adquiere el candado solo si
// nos hemos detenido o la cola
// no esta vacia
return stopped || ! intq.empty();
});
// Somos dueños del mutex aqui, salida de la cola
// hasta vaciarla.
while( ! intq.empty())
{
const auto val = intq.front();
intq.pop();
std::cout << "Consumidor saca: " << val << std::endl;
}
if(stopped){
// productor ha señalado una parada
std::cout << "Consumidor esta hecho!" << std::endl;
break;
}
}while(true);
}};
consumer.join();
producer.join();

std::cout << "¡Ejemplo completo!" << std::endl;


return 0;
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio02.cpp -o ejercicio02 -std=c++17 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 5
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 6

Ejercicio 3.
Implementar el siguiente código en c++ y guardarlo en un archivo código03.cpp:
#include <thread>
#include <mutex>
#include <condition_variable>
#include <syncstream>
#include <iostream>
using namespace std::chrono_literals;
struct Resource {
bool full = false;
std::mutex mux;
// Nota, el std::condition_variable solamente trabaja con c++20
// std::unique_lock<std::mutex>, para otras combinaciones
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 7

// usar std::condition_variable_any la cual puede ser menos eficiente.


std::condition_variable cond;
void produce() {
{
std::unique_lock lock(mux);
// espera hasta que la codicion es verdadera
// 1. el bloqueo se libera
// 2. cuando el thread es despertado, la cerradura es adquirida
// y la condición es verificada
// 3. si la condición es aun no verdadera, la cerradura
// es reliberdada, y vamos al paso 2.
// 4. si la condición es verdadera, el wait() llama para finalizar
cond.wait(lock, [this]{ return !full; });
std::osyncstream(std::cout) <<
"LLenando el recurso y notificando al consumidor.\n";
full = true;
std::this_thread::sleep_for(200ms);
}
// despierta un hilo esperando en esta variable de condición
// tenga en cuenta que ya liberamos nuestro bloqueo, de lo contrario
// el subproceso notificado se despertaría y no podría adquirir
// la cerradura y se suspende de nuevo
cond.notify_one();
}
void consume() {
{
std::unique_lock lock(mux);
// igual que arriba, pero con semántica opuesta
cond.wait(lock, [this]{ return full; });
std::osyncstream(std::cout) <<
"Consumiendo el recurso y notificando al productor.\n";
full = false;
std::this_thread::sleep_for(200ms);

}
cond.notify_one();
}
};
int main() {
Resource resource;
auto t1 = std::jthread([&resource](std::stop_token token){
while (!token.stop_requested())
resource.produce();
});
auto t2 = std::jthread([&resource](std::stop_token token){
while (!token.stop_requested())
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 8

resource.consume();
});
std::this_thread::sleep_for(2s);
t1.request_stop();
t2.request_stop();
// Nota: usar request_stop aquí no es seguro.
// Si eliminamos sleep_for, el subproceso t2 podría
// ejecuta un bucle completo antes de que se dé cuenta de la solicitud de parada
// y considerando que t1 ya no corre, el bloqueo
// la condición nunca se cumpliría.
// Esto se puede evitar usando condition_variable_any,
// que admite un token de parada o un tiempo de espera.
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio03.cpp -o ejercicio03 -std=c++20 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 9

Ejercicio 4.
Implementar el siguiente código en c++ y guardarlo en un archivo código04.cpp:
// conditionVariable.cpp
#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>
std::mutex mutex_;
std::condition_variable condVar;
void doTheWork(){
std::cout << "Procesando datos compartidos." << std::endl;
}
void waitingForWork(){
std::cout << "Worker: esperando por trabajo." << std::endl;
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck);
doTheWork();
std::cout << "Trabajo hecho." << std::endl;
}
void setDataReady(){
std::cout << "Enviador: Datos estan listos." << std::endl;
condVar.notify_one();
}
int main(){
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(setDataReady);
t1.join();
t2.join();
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 10

std::cout << std::endl;

}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio04.cpp -o ejercicio04 -std=c++20 -pthread

Ejercicio 5.
Implementar el siguiente código en c++ y guardarlo en un archivo código05.cpp:
#include <iostream>
#include <thread>
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 11

#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application()
{
m_bDataLoaded = false;
}
void loadData()
{
// haciendo que el thread duerma por 1 segundo
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout<<"Cargando datos desde el XML"<<std::endl;
// Cerrando la estructura de datos
std::lock_guard<std::mutex> guard(m_mutex);
// Ingresando la bandera como verdadera, significa que laos datos estan cargados
m_bDataLoaded = true;
// Notifica a la variable de condición
m_condVar.notify_one();
}
bool isDataLoaded()
{
return m_bDataLoaded;
}
void mainTask()
{
std::cout<<"Haciendo algo con las manos"<<std::endl;
// Adquiere la cerradura
std::unique_lock<std::mutex> mlock(m_mutex);
// Empezar a esperar a que se señale la variable de condición
// Wait() liberará internamente el bloqueo y hará que el hilo se bloquee
// Tan pronto como se señale la variable de condición, reanude el hilo y
// adquirir de nuevo el candado. Luego verifique si la condición se cumple o no
// Si se cumple la condición, continúe, de lo contrario, vuelva a esperar.
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
std::cout<<"Hacer procesamiento sobre los datos cargados"<<std::endl;
}
};
int main()
{
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 12

Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio05.cpp -o ejercicio05 -std=c++20 -pthread

Ejercicio 6.
Implementar el siguiente código en c++ y guardarlo en un archivo código06.cpp:
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 13

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Espere hasta que main () envíe datos
std::unique_lock lk(m);
cv.wait(lk, []{return ready;});
// después de la espera, somos dueños de la cerradura.
std::cout << "El thread Worker esta procesando datos\n";
data += " despues de procesar";
// Enviar datos de vuelta a main ()
processed = true;
std::cout << "Las senales de datos del thread Worker son procesadas completamente\n";
// El desbloqueo manual se realiza antes de notificar, para evitar despertar
// el hilo en espera solo para volver a bloquearse (ver notificar_uno para más detalles)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Data de ejemplo";
// enviar datos al hilo de trabajo
{
std::lock_guard lk(m);
ready = true;
std::cout << "main() los datos de las senales estan listos para ser procesados\n";
}
cv.notify_one();
// espera al trabajador
{
std::unique_lock lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Volviendo al main(), datos = " << data << '\n';
worker.join();
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 14

$g++ -W ejercicio06.cpp -o ejercicio06 -std=c++20 -pthread

Ejercicio 7
Implementar el siguiente código en c++ y guardarlo en un archivo código07.cpp:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 15

#include <thread>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
std::cout << "Worker iniciar thread " << std::endl;
std::unique_lock lk(m);
cv.wait(lk, [] { return ready; });
// Despues de wait, cerramos
std::cout << "Worker thread esta procesando datos" << std::endl;
data += " después de procesado ";
// Envia datos devuelta al master thread
processed = true;
std::cout << "Worker thread signals completa el procesamiento de datos " << std::endl;
// Liberado manual hecho antes que se notifique previniendo el despertar
// El thread despierta solamente para el bloque nuevamente
lk.unlock();
// El worker thread ha hecho su trabajo,
// Se notifica a master thread para continuar el trabajo.
cv.notify_one();
}
void master_thread()
{
std::cout << "Master thread inicia" << std::endl;
data = "Ejemplo de dato";
// Envia datos al worker thread.
{
std::lock_guard lk(m);
ready = true;
std::cout << "Los datos de Master thread signals listo para ser procesados"
<< std::endl;
}
// The mater thread ha hecho su trabajo preliminar,
// Notifica a worker thread para continuar el trabajo.
cv.notify_one();
// Esperando para el worker.
{
std::unique_lock lk(m);
cv.wait(lk, [] { return processed; });
}
std::cout << "Devuelta en master thread, datos = " << data << std::endl;
}
int main()
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 16

{
std::thread worker(worker_thread), master(master_thread);
// Workflow:
// master thread -> worker thread -> master thread.
worker.join();
master.join();
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio07.cpp -o ejercicio07 -std=c++20 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 17

Ejercicio 8.
Implementar el siguiente código en c++ y guardarlo en un archivo código08.cpp:
#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
std::condition_variable_any cv;
std::mutex cv_m;
int i;
void waits(int idx)
{
std::unique_lock<std::mutex> lk(cv_m);
if(cv.wait_for(lk, idx*100ms, []{return i == 1;}))
std::cerr << "Thread " << idx << " espera finalizada. i == " << i << '\n';
else
std::cerr << "Thread " << idx << " tiempo fuera. i == " << i << '\n';
}
void signals()
{
std::this_thread::sleep_for(120ms);
std::cerr << "Ntificando...\n";
cv.notify_all();
std::this_thread::sleep_for(100ms);
{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
}
std::cerr << "Notificando de nuevo...\n";
cv.notify_all();
}
int main()
{
std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
t1.join();
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 18

t2.join();
t3.join();
t4.join();
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio08.cpp -o ejercicio08 -std=c++20 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 19

Ejercicio 9
Implementar el siguiente código en c++ y guardarlo en un archivo código09.cpp:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Dormir el worker thread por 1 segundo y que la variable de condición
// es notificada en el master thread antes que la variable de condición inicie
// esperar en el worker thread.
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Worker thread inicia" << std::endl;
std::unique_lock lk(m);
// A menos que se produzca una reactivación espuria, el hilo será bloqueado
// porque la variable de condición no recibe ninguna notificación.
cv.wait(lk);
// Después de esperar , nos apoderamos de la cerradura.
std::cout << "Worker thread está procesando datos" << std::endl;
data += " después de procesado ";
// Envia datos de vuelta al master thread
processed = true;
std::cout << "Worker thread señala que los datos han sido procesados " << std::endl;
// Desbloqueo Manual hecho antes de notificar, para evitar desperat
// el hilo en espera solo para bloquearse nuevamente
lk.unlock();
cv.notify_one();
}
void master_thread()
{
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 20

std::cout << "Master thread inicia" << std::endl;


data = "Ejemplo de datos";
// Envia datos al worker thread.
{
std::lock_guard lk(m);
ready = true;
std::cout << "Master thread señala que los datos están listos para ser procesados "
<< std::endl;
}
// La variable de condición se notifica antes que la variable condicional de
// worker thread y master thread comienzan a esperar.
cv.notify_one();
// Wait for the worker.
{
std::unique_lock lk(m);
// El master thread es bloqueado la variable de condición no obtiene
// notificacion.
cv.wait(lk);
}
std::cout << "Devuelta en el master thread, datos = " << data << std::endl;
}
int main()
{
std::thread worker(worker_thread), master(master_thread);
worker.join();
master.join();
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio09.cpp -o ejercicio09 -std=c++20 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 21

Ejercicio 10
Implementar el siguiente código en c++ y guardarlo en un archivo código10.cpp:
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 22

#include <thread>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Dormir el worker thread por 1 segundo y que la variable de condición
// es notificada en el master thread antes que la variable de condición inicie
// esperar en el worker thread.
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Worker thread inicia" << std::endl;
std::unique_lock lk(m);
// Aunque se llama al método de espera, la variable condicional espera
// se omitirá si los datos ya están listos.
cv.wait(lk, [] { return ready; });
// Esto es equivalente a
// while (!ready())
// {
// wait(lock);
// }
// Despues de wait, nosotros somos dueños de la cerradura.
std::cout << "Worker thread esta procesando datos " << std::endl;
data += " después de procesador ";
// Envia datos de vuelta al master thread
processed = true;
std::cout << "Worker thread señala procesamiento de datos completado " << std::endl;
// El desbloqueo manual se realiza antes de notificar, para evitar despertar
// el thread en espera solo se bloquea nuevamente
lk.unlock();
cv.notify_one();
}
void master_thread()
{
std::cout << "Master thread inicia" << std::endl;
data = "Ejemplo de datos ";
// Envia datos para el worker thread.
{
std::lock_guard lk(m);
ready = true;
std::cout << "Master thread señala procesamiento de datos listos "
<< std::endl;
}
// La variable de condición se notifica antes que la variable condicional de
// el worker thread y el master thread comienzan a esperar.
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 23

cv.notify_one();
// Esperando por el worker.
{
std::unique_lock lk(m);
cv.wait(lk, [] { return processed; });
}
std::cout << "De vuelta al master thread, data = " << data << std::endl;
}
int main()
{
std::thread worker(worker_thread), master(master_thread);
worker.join();
master.join();
}
Para compilar este programa utilizamos el siguiente comando en línea de comandos
$g++ -W ejercicio10.cpp -o ejercicio10 -std=c++20 -pthread
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 24
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 25

II. SOLUCIÓN DE EJERCICIOS PROPUESTOS

Ejercicio 1. Modifique el ejercicio 01 para que se admita 50 threads:

He cambiado la constante 10 por num_threads y he establecido num_threads en 50. Esto asegura


que se creen y se utilicen 50 threads en lugar de 10. Ajusté el mensaje de salida para reflejar el
número correcto de threads también.

Código

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {


std::unique_lock<std::mutex> lck(mtx);
while (!ready) cv.wait(lck);
// ...
std::cout << "thread " << id << '\n';
}

void go() {
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();
}

int main() {
const int num_threads = 50; // Cambiado a 50 threads
std::thread threads[num_threads];

// Aparecen 50 threads
for (int i = 0; i < num_threads; ++i)
threads[i] = std::thread(print_id, i);

std::cout << num_threads << " threads listos para la carrera...\n";


go(); // Vamos

for (auto& th : threads)


th.join();
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 26

return 0;
}

Ejecución
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 27

Ejercicio 2. Modifique el ejercicio 08 para se pueda usar la función slep_until en lugar de slep_for

Reemplar sleep_for por std::this_thread::sleep_until en la función signals.


Modificar cv.wait_for por cv.wait_until en la función waits para que se use sleep_until en lugar de
sleep_for.
Añadí using namespace std::chrono; para facilitar el uso de unidades de tiempo.
Ahora, el código debería usar sleep_until en lugar de sleep_for para realizar la espera. Ten en cuenta
que sleep_until toma un argumento de tipo time_point, que se calcula sumando la duración actual a
la duración de espera.
Código

#include <iostream>
#include <atomic>
#include <condition_variable>
#include <thread>
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 28

#include <chrono>
using namespace std::chrono;

std::condition_variable_any cv;
std::mutex cv_m;
int i;

void waits(int idx)


{
std::unique_lock<std::mutex> lk(cv_m);

// Calcular el tiempo de espera en el futuro


auto wake_time = steady_clock::now() + milliseconds(idx * 100);

// Esperar hasta el tiempo especificado o hasta que i sea igual a 1


if (cv.wait_until(lk, wake_time, [] { return i == 1; }))
std::cerr << "Thread " << idx << " espera finalizada. i == " << i << '\n';
else
std::cerr << "Thread " << idx << " tiempo fuera. i == " << i << '\n';
}

void signals()
{
std::this_thread::sleep_for(120ms);
std::cerr << "Notificando...\n";
cv.notify_all();
std::this_thread::sleep_for(100ms);

{
std::lock_guard<std::mutex> lk(cv_m);
i = 1;
}

std::cerr << "Notificando de nuevo...\n";


cv.notify_all();
}

int main()
{
std::thread t1(waits, 1), t2(waits, 2), t3(waits, 3), t4(signals);
t1.join();
t2.join();
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 29

t3.join();
t4.join();
}
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 30

Ejecución

Ejercicio 3. Modifique el ejercicio 04 para que pueda admitir 4 threads más

Para modificar el ejercicio 04 para admitir 4 hilos más, simplemente podemos crear 4 hilos más
además de los dos existentes. Podemos hacer esto creando 4 instancias más de la clase std::thread
y llamando al método join() en los 6 subprocesos al final del programa.
Código
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 31

#include <iostream>
#include <condition_variable>
#include <mutex>
#include <thread>

std::mutex mutex_;
std::condition_variable condVar;

void doTheWork() {
std::cout << "Procesando datos compartidos." << std::endl;
}

void waitingForWork() {
std::cout << "Worker: esperando por trabajo." << std::endl;
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck);
doTheWork();
std::cout << "Trabajo hecho." << std::endl;
}

void setDataReady() {
std::cout << "Enviador: Datos estan listos." << std::endl;
condVar.notify_one();
}

int main() {
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(setDataReady);
std::thread t3(waitingForWork);
std::thread t4(setDataReady);
std::thread t5(waitingForWork);
std::thread t6(setDataReady);
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
t6.join();
std::cout << std::endl;
}
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 32

Ejecución
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 33

III. SOLUCIÓN DEL CUESTIONARIO


1 ¿Qué significa unique_lock?

std::unique_lock es una clase de biblioteca estándar de C++ que proporciona un contenedor de


propiedad mutex de uso general que permite bloqueo diferido, intentos de bloqueo con tiempo
limitado, bloqueo recursivo y transferencia de propiedad del bloqueo. Gestiona un objeto mutex con
propiedad única tanto en estado bloqueado como desbloqueado. A menudo se utiliza junto con
std::mutex para proteger los datos compartidos del acceso simultáneo de varios subprocesos.

Según Microsoft Learn[2], "El argumento de plantilla Mutex debe nombrar un tipo de exclusión
mutua. Internamente, un Unique_lock almacena un puntero en un objeto mutex".

El sitio web de desarrolladores de Android[3] explica que "unique_lock de C++ para proteger los
accesos a cualquier campo al... garantiza que se liberen correctamente los bloqueos en caso de una
excepción".

Características de std::unique_lock:

- Propiedad Única: std::unique_lock garantiza que solo un objeto tenga propiedad exclusiva del
mutex, ya sea en un estado bloqueado o desbloqueado.
- Bloqueos Diferidos: Permite bloqueos diferidos, lo que significa que el bloqueo del mutex no
es inmediato al crear el std::unique_lock, sino que puede ocurrir más adelante en el código.
- Intentos de Bloqueo con Límite de Tiempo: Puede realizar intentos de bloqueo con un límite
de tiempo, lo que es útil para evitar bloqueos indefinidos.
- Bloqueo Recursivo: Admite bloqueo recursivo, lo que significa que un hilo que ya tiene el
bloqueo puede volver a adquirirlo sin causar un bloqueo.
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLE-001 Página: 34

2 ¿Qué hace la librería atomic?

La biblioteca atómica en C++ proporciona soporte para operaciones atómicas en tipos de datos a los
que pueden acceder varios subprocesos simultáneamente. Garantiza que las operaciones se realicen
de forma atómica, lo que significa que son indivisibles y no pueden ser interrumpidas por otros
subprocesos. Esto es importante para prevenir condiciones de carrera y garantizar la seguridad de los
subprocesos en la programación concurrente[4].

La biblioteca atomic se utiliza para realizar operaciones atómicas en varios tipos de datos, como
números enteros, punteros y booleanos. Algunas de las clases comúnmente utilizadas en esta
biblioteca incluyen std::atomic, std::atomic_flag y std::atomic_ref [4].

En resumen, la biblioteca atomic proporciona una herramienta poderosa para garantizar la seguridad
de los subprocesos y prevenir condiciones de carrera en la programación concurrente al ofrecer
soporte para operaciones atómicas en tipos de datos compartidos. Esto asegura que las
actualizaciones y accesos a estos datos sean atómicos, evitando problemas relacionados con la
concurrencia.

REFERENCIAS Y BIBLIOGRAFÍA
[1] N Wolovick. 11 2002 Programación con Hilos: online, Available:
https://www.cs.famaf.unc.edu.ar/~nicolasw/Docencia/so2002/lab3.html
[2] “unique_lock (Clase)”. Microsoft Learn: Build skills that open doors in your career. Accedido el 20 de
noviembre de 2023. [En línea]. Disponible:
https://learn.microsoft.com/es-es/cpp/standard-library/unique-lock-class?view=msvc-170
[3] “Aspectos básicos de SMP para Android | Desarrolladores de Android | Android Developers”. Android
Developers. Accedido el 20 de noviembre de 2023. [En línea]. Disponible:
https://developer.android.com/training/articles/smp?hl=es-419
[4] “Aspectos básicos de SMP para Android | Desarrolladores de Android | Android Developers”. Android
Developers. Accedido el 20 de noviembre de 2023. [En línea]. Disponible:
https://developer.android.com/training/articles/smp?hl=es-419

También podría gustarte