
- •Список сокращений
- •Введение
- •Концепция потоков в ос
- •Понятие потока
- •Особенности организации потоков в ос Linux
- •Системный вызов clone
- •Библиотечные вызовы
- •Управление потоками
- •Синхронизация данных
- •Упражнения
- •Подготовка
- •Работа с многопоточностью
- •Пример применения многопоточности
- •Индивидуальные задания
- •Контрольные вопросы
- •Список литературы
Упражнения
Подготовка
В соответствии с п. 3.1 из Упражнений первой лабораторной работы подключитесь к командной оболочке Raspberry Pi.
Перейдите в каталог с вашими проектами:
cd IVT31_Ivanov_Ivan
Создайте директорию для файлов текущей лабораторной работы:
mkdir lab6_Фамилия
cd lab6_Фамилия
Работа с многопоточностью
Создайте файл thread.c и скопируйте в него данную программу. В ней происходит создание отдельного потока, который выводит на экран сообщения приветствия и прощания. Для компиляции воспользуйтесь следующим ключом:
gcc thread.c -o thread
-lpthread
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void *args)
{
printf("Hello from thread!\n");
printf("Goodbye from thread!\n");
}
int main()
{
pthread_t thread;
printf("Hello from main!\n");
pthread_create(&thread, NULL, func, NULL);
pthread_join(thread, NULL);
printf("Goodbye from main!\n");
return 0;
}
Запустите полученную программу. Убедитесь в том, что на экране появились сообщения:
Hello from main!
Hello from thread!
Goodbye from thread!
Goodbye from main!
Исправим программу таким образом, чтобы выводимая потоком строка передавалась в качестве аргумента
gcc thread.c -o thread
-lpthread
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *func(void *args)
{
printf("%s\n", (char*)args);
}
int main()
{
pthread_t thread;
char data[] = "Hello from thread!";
printf("Hello from main!\n");
pthread_create(&thread, NULL, func, (void*)data);
pthread_join(thread, NULL);
return 0;
}
В результате работы на экране появится сообщение:
Hello from main!
Hello from thread!
Создайте файл data_race.c и скопируйте в него данную программу. Данная программа в двух потоках изменяет значение глобальной переменной Global. Первый поток значение инкрементирует, второй – декрементирует. Для компиляции воспользуйтесь следующим ключом:
gcc data_race.c
-o data_race
-lpthread
#include <stdio.h>
#include <pthread.h>
#define N 1000000
int Global = 0;
void *Thread1()
{
for (size_t i = 0; i < N; i++)
Global++;
}
void *Thread2()
{
for (size_t i = 0; i < N; i++)
Global--;
}
int main()
{
pthread_t t1, t2;
pthread_create(&t1, NULL, Thread1, NULL);
pthread_create(&t2, NULL, Thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("%d\n", Global);
return 0;
}
Запустим программу несколько раз и убедимся, что значение переменной Global отличается от запуска к запуску из-за гонки данных.
Скорректируем программу таким образом, чтобы исправить ошибку. Для этого добавим в программу мьютекс. Перекомпилируем программу.
gcc data_race.c
-o data_race
-lpthread
#include <stdio.h>
#include <pthread.h>
#define N 1000000
int Global = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *Thread1()
{
pthread_mutex_lock(&mutex);
for (size_t i = 0; i < N; i++)
Global++;
pthread_mutex_unlock(&mutex);
}
void *Thread2()
{
pthread_mutex_lock(&mutex);
for (size_t i = 0; i < N; i++)
Global--;
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t t1, t2;
pthread_create(&t1, NULL, Thread1, NULL);
pthread_create(&t2, NULL, Thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
printf("%d\n", Global);
return 0;
}
Убедитесь, что при многократных запусках программы в результате на экране всегда будет выведен 0.