Zadania

  1. copy.c: Zmień implementację przykładu z kopiowaniem plików dołączonego do zajęć tak by nie wykorzystywać mutexów.

Sygnały

Typy atomowe

Wątki

Poniżej zaprezentowano przykładowe wykorzystanie wątków do równoległego kopiowania plików: Przykład można skompilować w kilku opcjach przez dodanie flagi (poprzez parametr -D kompilatora)

  • -DSEQUENTIAL w trybie bez wielowątkowości

  • w trybie wielowątkowym bez zabezpieczeń przed współbieżnym wykorzystaniem zasobów

  • -DGUARDED w trybie wielowątkowym z zabezpieczeniami przed współbieżnym wykorzystaniem zasobów

Przykład silnie inspirowany filmem „How to use threads in C++11”.

#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <stdio.h>

#define MiB (1024 * 1024)

static unsigned ln = 1;
static pthread_mutex_t io_mutex;

void Line(int l) {
	int m=l-ln; ln=l;
	if (m < 0) {
		printf("\r\33[%dA", -m);
	} else {
		putchar('\r');
		while (m-- > 0) putchar('\n');
	}
}

struct copy_args
{
	char const *from, *to;
	size_t howmuch;
	int line;
};

void* copy(struct copy_args *arg)
{
	int retval;
	int src = open(arg->from, O_RDONLY);
	int dst = open(arg->from, O_WRONLY);

	assert(src >= 0);
	assert(dst >= 0);

	for (size_t i = 0; i < arg->howmuch; ++i) {
		char c;
		read(src, &c, sizeof(c));
		write(src, &c, sizeof(c));
#ifdef GUARDED
		pthread_mutex_lock(&io_mutex);
#endif
		Line(arg->line);
		printf("%zu: %s -> %s: %2zu%%", pthread_self(), arg->from, arg->to, i * 100 / arg->howmuch);
		fflush(stdout);
#ifdef GUARDED
		pthread_mutex_unlock(&io_mutex);
#endif
	}

	return NULL;
}

int main()
{
	pthread_t thread;
	int ret;
	size_t line = 1;

	struct copy_args args[] = {
		{ "/dev/random", "/dev/null", 1   * MiB,  },
		{ "/dev/random", "/dev/null", 0.7 * MiB,  },
	};

	pthread_t threads[sizeof(args) / sizeof(*args)] = {};

#if defined(GUARDED)
	ret = pthread_mutex_init(&io_mutex, NULL);
	assert(ret >= 0);
#endif

	for (size_t i = 0; i < sizeof(args) / sizeof(*args); ++i) {
		args[i].line = line++;
#if defined(SEQUENTIAL)
		copy(&args[i]);
#else
		pthread_create(&threads[i], NULL, (void*(*)(void*))copy, &args[i]);
#endif
	}

#if !defined(SEQUENTIAL)
	for (size_t i = 0; i < sizeof(threads) / sizeof(*threads); ++i) {
		pthread_join(threads[i], NULL);
	}
#endif

	Line(line);
	fflush(stdout);
	return 0;
}