Skip to content

Instantly share code, notes, and snippets.

@j000
Last active June 12, 2018 18:28
Show Gist options
  • Save j000/f26db502605906af5f1ccf822d62587e to your computer and use it in GitHub Desktop.
Save j000/f26db502605906af5f1ccf822d62587e to your computer and use it in GitHub Desktop.
Czytelnicy i pisarze
#define _REENTRANT
#define _XOPEN_SOURCE 700
#include <pthread.h> /* wątki */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> // rand
#include <time.h> // time
#define PISARZE 2
#define CZYTELNICY 10
// man 3 pthread_mutex_destroy
pthread_mutex_t mutex_dostep = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_czytelnicy = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_kolejnosc = PTHREAD_MUTEX_INITIALIZER;
unsigned liczba_czytelnikow = 0;
// mój system narzeka, że usleep nie istnieje
// jeżeli usleep(1) działa: NIE KOPIUJ
#if _POSIX_VERSION >= 200800L
#define usleep my_usleep
__attribute__((always_inline)) inline
void usleep(unsigned long microseconds) {
struct timespec delay = {
.tv_sec = microseconds / 1000000l,
.tv_nsec = (microseconds % 1000000l) * 1000
};
while (nanosleep(&delay, &delay) == -1);
}
#endif
void *czytelnik(void *costam) {
int i = 5;
usleep(2000000 * drand48()); // losowe czekanie
while (--i) {
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
pthread_mutex_lock(&mutex_kolejnosc); // kolejka
pthread_mutex_lock(&mutex_czytelnicy); // dostęp do licznika czytelników
if (liczba_czytelnikow == 0) // pierwszy czytelnik
pthread_mutex_lock(&mutex_dostep); // uzyskuje dostęp do biblioteki
++liczba_czytelnikow;
pthread_mutex_unlock(&mutex_czytelnicy); // koniec dostępu do licznika
pthread_mutex_unlock(&mutex_kolejnosc); // koniec kolejki, jesteśmy w środku
// czytaj...
printf("Czytelnik\n");
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
printf("Poczytałem\n");
pthread_mutex_lock(&mutex_czytelnicy); // dostęp do licznika czytelników
--liczba_czytelnikow;
if (liczba_czytelnikow == 0) // ostatni czytelnik
pthread_mutex_unlock(&mutex_dostep); // gasi światłoi ;)
pthread_mutex_unlock(&mutex_czytelnicy); // koniec dostępu do licznika
}
return NULL;
}
void *pisarz(void *costam) {
int i = 5;
usleep(2000000 * drand48()); // losowe czekanie
while (--i) {
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
pthread_mutex_lock(&mutex_kolejnosc); // kolejka
pthread_mutex_lock(&mutex_dostep); // dostęp do biblioteki
pthread_mutex_unlock(&mutex_kolejnosc); // koniec kolejki, jesteśmy w środku
// zapisz...
printf(" *** Pisarz ***\n");
usleep(2000000 * drand48());
printf(" *** Zapisane ***\n");
pthread_mutex_unlock(&mutex_dostep); // wpuść kogoś innego do biblioteki
}
return NULL;
}
int main() {
srand48(time(NULL));
pthread_t pisarze[PISARZE] = {0};
pthread_t czytelnicy[CZYTELNICY] = {0};
// tworzymy wątki pisarzy
for (unsigned i = 0; i < PISARZE; ++i) {
if (pthread_create(&(pisarze[i]), NULL, pisarz, NULL)) {
printf("pthread_create(pisarz) failed\n");
_exit(1);
}
usleep(100);
}
// tworzymy wątki czytelników
for (unsigned i = 0; i < CZYTELNICY; ++i) {
if (pthread_create(&(czytelnicy[i]), NULL, czytelnik, NULL)) {
printf("pthread_create(czytelnik) failed\n");
_exit(1);
}
usleep(100);
}
usleep(1000000);
// czekamy na wątki pisarzy
for (unsigned i = 0; i < PISARZE; ++i) {
if (pthread_join(pisarze[i], NULL)) {
printf("pthread_join() failed\n");
_exit(1);
}
}
// czekamy na wątki czytelników
for (unsigned i = 0; i < CZYTELNICY; ++i) {
if (pthread_join(czytelnicy[i], NULL)) {
printf("pthread_join() failed\n");
_exit(1);
}
}
pthread_mutex_destroy(&mutex_czytelnicy);
pthread_mutex_destroy(&mutex_dostep);
pthread_mutex_destroy(&mutex_kolejnosc);
return 0;
}
// vim: tabstop=4 shiftwidth=0 noexpandtab
#define _REENTRANT
#define _XOPEN_SOURCE 700
#include <pthread.h> /* wątki */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> // rand
#include <time.h> // time
#define PISARZE 2
#define CZYTELNICY 10
// man 3 pthread_rwlock_destroy
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
// mój system narzeka, że usleep nie istnieje
// jeżeli usleep(1) działa: NIE KOPIUJ
#if _POSIX_VERSION >= 200800L
#define usleep my_usleep
__attribute__((always_inline)) inline
void usleep(unsigned long microseconds) {
struct timespec delay = {
.tv_sec = microseconds / 1000000l,
.tv_nsec = (microseconds % 1000000l) * 1000
};
while (nanosleep(&delay, &delay) == -1);
}
#endif
void *czytelnik(void *costam) {
int i = 5;
usleep(2000000 * drand48()); // losowe czekanie
while (--i) {
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
pthread_rwlock_rdlock(&rwlock);
// czytaj...
printf("Czytelnik\n");
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
printf("Poczytałem\n");
pthread_rwlock_unlock(&rwlock);
}
return NULL;
}
void *pisarz(void *costam) {
int i = 5;
usleep(2000000 * drand48()); // losowe czekanie
while (--i) {
// rand itp. nie powinny być uzywane równocześnie z kilku wątków
// grozi błędem
usleep(2000000 * drand48());
pthread_rwlock_wrlock(&rwlock);
// zapisz...
printf(" *** Pisarz ***\n");
usleep(2000000 * drand48());
printf(" *** Zapisane ***\n");
pthread_rwlock_unlock(&rwlock);
}
return NULL;
}
int main() {
srand48(time(NULL));
pthread_t pisarze[PISARZE] = {0};
pthread_t czytelnicy[CZYTELNICY] = {0};
// tworzymy wątki pisarzy
for (unsigned i = 0; i < PISARZE; ++i) {
if (pthread_create(&(pisarze[i]), NULL, pisarz, NULL)) {
printf("pthread_create(pisarz) failed\n");
_exit(1);
}
usleep(100);
}
// tworzymy wątki czytelników
for (unsigned i = 0; i < CZYTELNICY; ++i) {
if (pthread_create(&(czytelnicy[i]), NULL, czytelnik, NULL)) {
printf("pthread_create(czytelnik) failed\n");
_exit(1);
}
usleep(100);
}
usleep(1000000);
// czekamy na wątki pisarzy
for (unsigned i = 0; i < PISARZE; ++i) {
if (pthread_join(pisarze[i], NULL)) {
printf("pthread_join() failed\n");
_exit(1);
}
}
// czekamy na wątki czytelników
for (unsigned i = 0; i < CZYTELNICY; ++i) {
if (pthread_join(czytelnicy[i], NULL)) {
printf("pthread_join() failed\n");
_exit(1);
}
}
pthread_rwlock_destroy(&rwlock);
return 0;
}
// vim: tabstop=4 shiftwidth=0 noexpandtab
# Jarosław Rymut
### 'private' wymaga przynajmniej GNU make 3.82 z 2010 roku ###
# numer zestawu
zestaw := $(notdir $(lastword $(CURDIR)))
# nazwa spakowanego pliku
tar := Rymut_$(zestaw).tar.gz
# flagi
CFLAGS := -std=c99 -O2 -Wall -Wextra
ARFLAGS += -c -s
ifeq ($(shell $(CC) -dumpversion),4.7)
# welcome to 2012
# -Wpedantic is available since gcc 4.8
CFLAGS += -pedantic
else
CFLAGS += -Wpedantic
endif
# CFLAGS += -fPIC -fPIE
# LDFLAGS += -fPIC -fPIE -pie
# PIC > PIE > no-pie
CFLAGS += -fPIC
LDFLAGS += -fPIC -pie
LDLIBS += -Wl,-R.
LOADLIBES += -lpthread
CFLAGS += -flto
HELPERS := sem.c shmem.c
FILES := $(filter-out $(HELPERS),$(wildcard *.c))
.PHONY: all
all: $(FILES:.c=.x)
.PHONY: clean
clean:
-$(RM) $(FILES:.c=.x) $(tar) lib*
.PHONY: tar
tar:
# poprawka na błąd 'file changed as we read it'
[ -f $(tar) ] || touch $(tar)
tar -caf ./$(tar) --exclude=$(tar) --exclude=*.x --exclude=.* --exclude=lib* -C .. $(zestaw)
# kopia wbudowanej reguły, z nowym rozszerzeniem
%.x: private LDFLAGS += -fPIC -pie
%.x: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) $(OUTPUT_OPTION)
# kopia wbudowanej reguły, z nowym rozszerzeniem
lib%.so: private LDFLAGS += -shared
lib%.so: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) $(OUTPUT_OPTION)
####################
# wszystko zależy od Makefile
$(FILES:.c=.o) $(HELPERS:.c=.o): Makefile
####################
# make może usunąć pliki "tymczasowe"
.INTERMEDIATE: $(HELPERS:.c=.o) $(FILES:.c=.o)
####################
# # wszystko potrzebuje biblioteki
# $(FILES:.c=.x): private LDLIBS += -L. -lsem -lshmem
#
# # wszystko zależy od shmem.h
# $(FILES:.c=.o): sem.h | libsem.so libshmem.so
# sem.o: sem.h
# shmem.o: shmem.h
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment