No New New: Raw Pointers Removed from C++

Two weeks ago, the ISO C++ standard meeting took place in Jacksonville. Today I want to make a short detour and write about the revolutionary decision that was made in the Jacksonville meeting. Additionally, I refer to the Will no Longer Have Pointers by Fluent C++. The standard committee decided that pointers will be deprecated in C++20 and will with very high probability removed in C++23.

To be honest, what seems like a revolution is only the last step in a long evolution. First, let me explain the big picture.

 The evolution of pointers in C++

Pointers are part of C++ since the first beginning. We got them from C. From the first beginning there was always the tendency in C++ to make the handling with pointers more type-safe without paying the extra cost.

With C++98 we got std::auto_ptr to express exclusive ownership. But std::auto_ptr had a big issue. When you copy an std::auto_ptr the resource will be moved. What looks like a copy operation was actually a move operation. The graphic shows the surprising behaviour of an std::auto_ptr.

This was extremely bad and the reason for a lot of serious bugs; therefore, we got std::unique_ptr with C++11 and std::auto_ptr was deprecated in C++11 and finally removed in C++17. Additionally, we got std::shared_ptr and std::weak_ptr in C++11 for handling shared ownership. You can not copy but move an std::unique_ptr and if you copy or assign an std::shared_ptr, the internal reference counter will be increased. Have a look here:

Since C++11 C++ has a multithreading library. This makes the handling with std::shared_ptr quite challenging because an std::shared_ptr is per definition shared but not thread-safe. Only the control-block is thread-safe but not the access to its resource. That means, modifying the reference counter is an atomic operation and you have the guarantee that the resource will be deleted exactly once. This is the reason we will get with C++20 atomic smart pointers: std::atomic_shared_ptr and std::atmic_weak_ptr. Read the details in the proposal: Atomic Smart Pointers.

5 Best Eclipse Plugins: #1 (Eclox with Doxygen, Graphviz and Mscgen) | MCU on Eclipse

5 Best Eclipse Plugins: #1 (Eclox with Doxygen, Graphviz and Mscgen)Posted on June 25, 2012 by Erich Styger 24 VotesThe #1 award in my list goes to Eclox+Doxygen+Graphviz+Mscgen. Yes, it is a single Eclipse plugin (Eclox) for Doxygen, and with two other powerful tools. It solves a typical engineering problem: “How to document my project? And how to keep it up-to-date?”. Like many other engineers, I do not like to write documentation. Because it is painful. I want to write code and program. Writing documentation for it should be fun too. And it should solve the problem that the documentation does not match what has been implemented. I’m a big fan of the ‘single source’ concept: information has to be in a single place, and not copied and distributed among different places. And here my #1 helps me doing this.In a traditional way the following flow is used: Create a design, specify and document the API Implement the software Write the user documentation Ship it Maintain and ship and again, and again, and

Source: 5 Best Eclipse Plugins: #1 (Eclox with Doxygen, Graphviz and Mscgen) | MCU on Eclipse

Usefully for write and maintenance plugin for Eclipse…

  1. Doxygen: http://www.stack.nl/~dimitri/doxygen/ or www.doxygen.org
  2. Graphviz: http://www.graphviz.org
  3. Mscgen: http://www.mcternan.me.uk/mscgen/

after this article i use all of them.

Arrays of Pointers

9.4 Arrays of Pointers

As seen in the last example, sorting an array of strings requires swapping the strings which can require copying a lot of data. For efficiency, it is better to avoid actual swapping of data whenever a data item is large, such as a string or an entire data base record. In addition, arrays may be needed in more than one order; for example, we may need an exam scores array sorted by Id number and by weighted scores; or, we may need strings in both an unsorted form and a sorted form.
In either of these cases, we must either keep two copies of the data, each sorted differently, or find a more efficient way to store the data structure. The solution is to use pointers to elements of the array and swap pointers. Consider some examples:

int data1, data2, *ptr1, *ptr2, *save;
data1 = 100; 
data2 = 200; 
ptr1 = *data1; 
ptr2 = *data2;

We could swap the values of the data and store the swapped values in data1 and data2 or we could simply swap the values of the pointers:

save = ptr1;
ptr1 = ptr2;
ptr2 = save;

We have not changed the values in

data1

and data2 but ptr1 now accesses data2 and ptr2 access data1. We have swapped the pointer values so they point to objects in a different order. We can apply the same idea to strings:

char name1[] = "John";
char name2[] = "Dave";
char *p1, *p2, *save;
p1 = name1; 
p2 = name2;

Pointers p1 and p2 point to strings name1 and name2. We can now swap the pointer values so p1 and p2 point to name2 and name1, respectively.

In general, an array of pointers can be used to point to an array of data items with each element of the pointer array pointing to an element of the data array. Data items can be accessed either directly in the data array, or indirectly by dereferencing the elements of the pointer array. The advantage of a pointer array is that the pointers can be reordered in any manner without moving the data items. For example, the pointer array can be reordered so that the successive elements of the pointer array point to data items in sorted order without moving the data items. Reordering pointers is relatively fast compared to reordering large data items such as data records or strings. This approach saves a lot of time, with the additional advantage that the data items remain available in the original order. Let us see how we might implement such a scheme.

STRPTRS: Given an array of strings, use pointers to order the strings in sorted form, leaving the array unchanged.

We will use an array of character pointers to point to the strings declared as follows:

char * nameptr[MAX];

The array, nameptr[], is an array of size MAX, and each element of the array is a character pointer. It is then possible to assign character pointer values to the elements of the array; for example:

nameptr[i] = "John Smith";

The string "John Smith" is placed somewhere in memory by the compiler and the pointer to the string constant is then assigned to nameptr[i]. It is also possible to assign the value of any string pointer to nameptr[i]; for example, if s is a string, then it is possible to assign the pointer value s to nameptr[i]:

nameptr[i] = s;

In particular, we can read strings into a two dimensional array, names[][], and assign each string pointer, names[i] to the element of the pointer array, nameptr[]:

for (i = 0; i < MAX && gets(names[i]); i++)
          nameptr[i] = names[i];

The strings can then be accessed either by names[i] or by nameptr[i] as seen in Figure 9.4. We can then reorder the pointers in nameptr[] so that they successively point to the strings in sorted order as seen in Figure 9.4. We can then print the strings in the original order by accessing them through names[i]and print the strings in sorted order by accessing them through nameptr[i]. Here is the algorithm

/**
 * Zadania
 * -------
 * z1: Napisz program, który pokazuje, które atrybuty procesu macierzystego są dziedziczone przez proces potomny  uruchomiony za pomocą funkcji fork(), które zaś otrzymują nową wartość.
 * z2: Napisz program, który pokazuje, które atrybuty procesu są zachowane przez proces po wykonaniu funkcji exec().
 * z3: Napisz program, który wyświetla identyfikator procesu (PID) i nazwę związanego z nim polecenia dla wszystkich procesów uruchomionych przez użytkownika podanego w wierszu wywołania programu. Wskazówka: informacje te można uzyskać przeglądając katalog /proc z plików (interesują nas katalogi, których właścicielem jest dany  użytkownik) i pliki /proc/PID/status
 *
 * Każdy proces charakteryzuje się pewnymi atrybutami. Należą do nich:
 * Identyfikator procesu PID
 * Identyfikator procesu macierzystego PPID
 * Rzeczywisty identyfikator właściciela procesu
 * Rzeczywisty identyfikator grupy procesu
 * Efektywny identyfikator właściciela procesu
 * Efektywny identyfikator grupy procesu
 * Katalog bieżący i katalog główny
 * Maska tworzenia pliku
 * Identyfikator sesji
 * Terminal sterujący
 * Deskryptory otwartych plików
 * Ustalenia dotyczące obsługi sygnałów
 * Ustawienia zmiennych środowiskowych
 * Ograniczenia zasobów
 *
 *
 * Potomek dziedziczy z procesu potomnego wiele własności:
 rzeczywisty identyfikator użytkownika, rzeczywisty identyfikator grupy, obowiązujący identyfikator użytkownika, obowiązujący identyfikator grupy,
 identyfikatory dodatkowych grup,
 identyfikator sesji,
 terminal sterujący,
 sygnalizator ustanowienia identyfikatora użytkownika oraz sygnalizator ustanowienia identyfikatora grupy,
 deskryptory otwartych plików (są kopiowane)
 bieżący katalog roboczy,
 katalog główny,
 maskę tworzenia plików,
 maskę sygnałów oraz dyspozycje obsługi sygnałów,
 sygnalizator zamykania przy wywołaniu funkcji exec (close-on-exec) dla wszystkich otwartych deskryptorów plików,
 środowisko,
 przyłączone segmenty pamięci wspólnej,
 ograniczenia zasobów systemowych.
 Są jednak pewne różnice między procesem macierzystym a potomnym:
 wartość powrotu z funkcji fork,
 różne identyfikatory procesów,
 inne identyfikatory procesów macierzystych - w procesie potomnym jest to identyfikator procesu macierzystego; w procesie macierzystym identyfikator procesu macierzystego nie zmienia się,
 w procesie potomnym wartości tms_utime, tms_cutime i tms_ustime są równe 0,
 potomek nie dziedziczy rygli plików, ustalonych w procesie macierzystym,
 w procesie potomnym są zerowane wszystkie zaległe alarmy,
 w procesie potomnym jest zerowany zbiór zaległych sygnałów.
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

extern char** environ;
char *prt_parent;

int glob = 1;           // zewnętrzna zmienna

/* Prints the environment, one environment variable to a line, of the process given by PID. */
char *print_process_environment(pid_t pid) {
    int fd;
    char filename[24];
    char environment[8192];
    size_t length;
    char* next_var;
    /* Generate the name of the environ file for the process. */
    snprintf(filename, sizeof(filename), "/proc/%d/environ", (int) pid);
    /* Read the contents of the file. */
    fd = open(filename, O_RDONLY);
    length = sizeof(environ);
    printf("Size of environ: %d\n", length);
    close(fd);
    /* read does not NUL-terminate the buffer, so do it here. */
    environment[length] = '\0';
    /* Loop over variables. Variables are separated by NULs. */
    next_var = environment;
    while (next_var < environment + length) { /* Print the variable. Each is NUL-terminated, so just treat it like an ordinary string. */ printf(">> %s\n", next_var);
        /* Advance to the next variable. Since each variable is
         NUL-terminated, strlen counts the length of the next variable,
         not the entire variable list. */
        next_var += strlen(next_var) + 1;
    }
    return (environment);
}


int main(int argc, char **argv) {
    int var = 100;              // zmienna automatyczna na stows
    char **env = environ;       // środowisko parent
    // zapamiętanie environ w tablicy

    printf("PROGRAM Z1\n\n");
    printf("Zmienne srodowiskowe parent: ----------------------------\n");
    while (*env) {
        printf("%s\n", *env++);
    }

    printf("---------------------------------------------------------\n");
    
    for (int i = 0; *env != NULL && gets(env[i]); i++)
              nameptr[i] = env[i];
    
    pid_t pid = fork();

    if (pid == 0) {
        // child process
        glob++;
        var++;
        printf("child process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
                glob, var);

        /**
         * wy swietlenie zmiennych środowiskowych różnych od parent
         */
        printf("Zmienne srodowiskowe child różne od parent:\n");
        char environment_1[8192];
        char * prt_env = &environment_1;
        prt_env = print_process_environment(pid);
        char **env_child = environ;
        printf("Size of *char: %d\n", sizeof(environ));

        while (*env_child) {
            printf("compare - %s %d\n", *env_child, strcmp(*env_child++, *env++));
            //printf("%s -----\n", *env2++);
            //if (strcmp(*env2, ++*env) == 0) {
            //
            //} else {
            //printf("%s jest takie samo\n", *env2);
            //}
            //*env_child++;
            //*env++;
        }
        printf("-------------------- x --------------------\n");

    } else if (pid > 0) {
        // parent process
        printf("parent process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
                glob, var);
    } else {
        // fork failed
        printf("fork() failed!\n");
        return (1);
    }

    printf("-- end of program pid %d\n", getpid());

    return (0);
}

Programowanie współbieżne C na Linux – przykłady

Przykładowe zadania z programowania współbieżnego na systemie Linux

  1. Napisz program, który pokazuje, które atrybuty procesu macierzystego są dziedziczone przez proces potomny uruchomiony za pomocą funkcji fork(), które zaś otrzymują nową wartość.
  2. Napisz program, który pokazuje, które atrybuty procesu są zachowane przez proces po wykonaniu funkcji exec().
  3. Napisz program, który wyświetla identyfikator procesu (PID) i nazwę związanego z nim polecenia dla wszystkich procesów uruchomionych przez użytkownika podanego w wierszu wywołania programu.
/**
 * Uzupełnij program shell z o „ręczną” obsługę potoków.
 * ----------------------------------------------------
 * Napisz program, który zbiera komunikaty od wielu programów i wyświetla je na ekranie. Do komunikacji użyj potoku nazwanego.
 *
 * Wskazówka: Utwórz program rdfifo, którego zadaniem jest utworzenie kolejki FIFO i czytanie z niej danych.
 * Utwórz program wrfifo, który otwiera kolejkę FIFO tylko do zapisu i wpisuje do niej dane (np. swoj pid i czas).
 *
 * Q: W jaki sposób przekażesz wspólną nazwę kolejki FIFO do tych programów?
 * A: przez zmienną statyczą
 *
 * Q: W jaki sposób zapewnić działanie programu zbierającego komunikaty również wtedy, kiedy nie ma programu piszącego do łącza?
 * A: przez proces pętli nieskończonej ze sleep
 *
 * Q: Jak zapewnić to, że komunikaty pochodzące od różnych programów wyświetlane są w całości, tzn. nie są rozdzielane  komunikatami od innych programów?
 * A: flush? (do sprawdzenia).
 *
 */

Wskazówka: informacje te można uzyskać przeglądając katalog /proc z plików (interesują nas katalogi, których właścicielem jest dany użytkownik) i pliki /proc/PID/status

Sources

C programing tutorial

 

Example solution 1 (draft)

# README #



## Uzupełnij program shell z o „ręczną” obsługę potoków.

Napisz program, który zbiera komunikaty od wielu programów i wyświetla je na ekranie. Do komunikacji użyj potoku nazwanego. Wskazówka: Utwórz program rdfifo, którego zadaniem jest utworzenie kolejki FIFO i czytanie z niej danych.

* Q: W jaki sposób przekażesz wspólną nazwę kolejki FIFO do tych programów?
* A: przez zmienną statyczą
* Q: W jaki sposób zapewnić działanie programu zbierającego komunikaty również wtedy, kiedy nie ma programu piszącego do łącza?
* A: przez proces pętli nieskończonej ze sleep
* Q: Jak zapewnić to, że komunikaty pochodzące od różnych programów wyświetlane są w całości, tzn. nie są rozdzielane  komunikatami od innych programów?
* A: flush? (do sprawdzenia).

### Zrzut z działania:

```
[23:30:20](pid 17400) DEBUG: Passed rdfifo 73 - while1

karol@carlo:~/eclipse-workspaces/unx_sys_programming/Debug$ ./unx_sys_programming -w

Input option value=(null) set program to write to FIFO

[23:30:20](pid 17411) DEBUG: Passed wrfifo 148 : mkfifo exist: 17
[23:30:20](pid 17411) DEBUG: Passed wrfifo 157 - pipe opened to read-write
[23:30:20](pid 17400) DEBUG: Passed rdfifo 104 - Remove FIFO
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #0 test PID: 17411: text -> Thu Jan 28 23:36:02 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #0 test PID: 17411: text -> Thu Jan 28 23:36:02 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #1 test PID: 17411: text -> Thu Jan 28 23:36:03 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #1 test PID: 17411: text -> Thu Jan 28 23:36:03 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #2 test PID: 17411: text -> Thu Jan 28 23:36:04 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #2 test PID: 17411: text -> Thu Jan 28 23:36:04 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #3 test PID: 17411: text -> Thu Jan 28 23:36:05 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #3 test PID: 17411: text -> Thu Jan 28 23:36:05 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #4 test PID: 17411: text -> Thu Jan 28 23:36:06 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #4 test PID: 17411: text -> Thu Jan 28 23:36:06 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #5 test PID: 17411: text -> Thu Jan 28 23:36:07 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #5 test PID: 17411: text -> Thu Jan 28 23:36:07 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #6 test PID: 17411: text -> Thu Jan 28 23:36:08 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #6 test PID: 17411: text -> Thu Jan 28 23:36:08 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #7 test PID: 17411: text -> Thu Jan 28 23:36:09 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #7 test PID: 17411: text -> Thu Jan 28 23:36:09 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #8 test PID: 17411: text -> Thu Jan 28 23:36:10 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #8 test PID: 17411: text -> Thu Jan 28 23:36:10 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #9 test PID: 17411: text -> Thu Jan 28 23:36:11 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #9 test PID: 17411: text -> Thu Jan 28 23:36:11 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 180 - close fd
[23:30:20](pid 17400) DEBUG: Passed rdfifo 112 - EOF reader

[10]   Done                    ./unx_sys_programming -r

bash:~/eclipse-workspaces/unx_sys_programming/Debug$ ./unx_sys_programming -h

Program FIFO
Program bez argumentów tworzy named pipe a w procesie potomnym zapisuje do niego dane.
Program mozna wywołać z argumentami tak aby działał jako odczyt (r) z pipe lub zapis do pipe (w).
Zapisywane są do pipe couner, PID i curenttime.

Usage: ./unx_sys_programming [-r] [-w]
```

## Przykład użycia


```
./unx_sys_programming

```

lub


```
./unx_sys_programming -r
./unx_sys_programming -w
./unx_sys_programming -w
./unx_sys_programming -w
```

# Fork read environ - zadania

* z1: Napisz program, który pokazuje, które atrybuty procesu macierzystego są dziedziczone przez proces potomny  uruchomiony za pomocą funkcji fork(), które zaś otrzymują nową wartość.
* z2: Napisz program, który pokazuje, które atrybuty procesu są zachowane przez proces po wykonaniu funkcji exec().
* z3: Napisz program, który wyświetla identyfikator procesu (PID) i nazwę związanego z nim polecenia dla wszystkich procesów uruchomionych przez użytkownika podanego w wierszu wywołania programu. Wskazówka: informacje te można uzyskać przeglądając katalog /proc z plików (interesują nas katalogi, których właścicielem jest dany  użytkownik) i pliki /proc/PID/status
 
Każdy proces charakteryzuje się pewnymi atrybutami. Należą do nich

 * Identyfikator procesu PID
 * Identyfikator procesu macierzystego PPID
 * Rzeczywisty identyfikator właściciela procesu
 * Rzeczywisty identyfikator grupy procesu
 * Efektywny identyfikator właściciela procesu
 * Efektywny identyfikator grupy procesu
 * Katalog bieżący i katalog główny
 * Maska tworzenia pliku
 * Identyfikator sesji
 * Terminal sterujący
 * Deskryptory otwartych plików
 * Ustalenia dotyczące obsługi sygnałów
 * Ustawienia zmiennych środowiskowych
 * Ograniczenia zasobów
 
Potomek dziedziczy z procesu potomnego wiele własności: rzeczywisty identyfikator użytkownika, rzeczywisty identyfikator grupy, obowiązujący identyfikator użytkownika, obowiązujący identyfikator grupy, identyfikatory dodatkowych grup, identyfikator sesji, terminal sterujący, sygnalizator ustanowienia identyfikatora użytkownika oraz sygnalizator ustanowienia identyfikatora grupy, deskryptory otwartych plików (są kopiowane) bieżący katalog roboczy, katalog główny,
 maskę tworzenia plików, maskę sygnałów oraz dyspozycje obsługi sygnałów, sygnalizator zamykania przy wywołaniu funkcji exec (close-on-exec) dla wszystkich otwartych deskryptorów plików, środowisko, przyłączone segmenty pamięci wspólnej,
 ograniczenia zasobów systemowych. Są jednak pewne różnice między procesem macierzystym a potomnym:
 wartość powrotu z funkcji fork, różne identyfikatory procesów, inne identyfikatory procesów macierzystych - w procesie potomnym jest to identyfikator procesu macierzystego; w procesie macierzystym identyfikator procesu macierzystego nie zmienia się, w procesie potomnym wartości tms_utime, tms_cutime i tms_ustime są równe 0,
 potomek nie dziedziczy rygli plików, ustalonych w procesie macierzystym, w procesie potomnym są zerowane wszystkie zaległe alarmy, w procesie potomnym jest zerowany zbiór zaległych sygnałów.

#include <asm-generic/errno-base.h>

/**
 * Uzupełnij program shell z o „ręczną” obsługę potoków.
 * ----------------------------------------------------
 * Napisz program, który zbiera komunikaty od wielu programów i wyświetla je na ekranie. Do komunikacji użyj potoku nazwanego.
 *
 * Wskazówka: Utwórz program rdfifo, którego zadaniem jest utworzenie kolejki FIFO i czytanie z niej danych.
 * Utwórz program wrfifo, który otwiera kolejkę FIFO tylko do zapisu i wpisuje do niej dane (np. swoj pid i czas).
 *
 * Q: W jaki sposób przekażesz wspólną nazwę kolejki FIFO do tych programów?
 * A: przez zmienną statyczą
 *
 * Q: W jaki sposób zapewnić działanie programu zbierającego komunikaty również wtedy, kiedy nie ma programu piszącego do łącza?
 * A: przez proces pętli nieskończonej ze sleep
 *
 * Q: Jak zapewnić to, że komunikaty pochodzące od różnych programów wyświetlane są w całości, tzn. nie są rozdzielane  komunikatami od innych programów?
 * A: flush? (do sprawdzenia).
 *
 */
#define DEBUG_MODE

#ifdef DEBUG_MODE
#define logs(...) printf("[%s](pid %d) DEBUG: Passed %s %d - %s\n", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define logs_d(...) printf("[%s](pid %d) DEBUG: Passed %s %d - %s : %d\n", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define logs(...)
#endif

#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#define FIFOARG 1
#define PIPE_BUF 100
#define FIFO_PERMS (S_IRWXU | S_IWGRP| S_IWOTH)
#define FIFO "temp.fifo"

#define BUFFERSIZE 500000
char buf[BUFFERSIZE]; // read buf

char* mygettime() {
	time_t mytime;
	mytime = time(NULL);
	return (ctime(&mytime));
}

/**
 * Serwer read from named pipe
 * -----------------
 * @param argc
 * @param argv
 * @return
 */
int rdfifo() {

	int fifo, var;

	/* There are *two* ways the open can fail: the pipe doesn't exist
	 * yet, *or* it succeeded, but a different writer already opened
	 * it but didn't yet remove it.
	 */
	logs("reader start");
	while (1) {
		logs("while1");
		while ((fifo = open(FIFO, O_RDONLY)) == -1) {
			/* Since you didn't specify O_CREAT in the call to open, there
			 * is no way that FIFO would have been created by the
			 * reader.  If there *is* now a FIFO, a remove here
			 * would delete the one the writer created!
			 */
			sleep(1);
		}

		/* Get an exclusive lock on the file, failing if we can't get
		 * it immediately.  Only one reader will succeed.
		 */
		if (flock(fifo, LOCK_EX | LOCK_NB) == 0)
			break;

		/* We lost the race to another reader.  Give up and wait for
		 * the next writer.
		 */
		close(fifo);
	}
	/* We are definitely the only reader.
	 */

	/* *Here* we delete the pipe, now that we've locked it and thus
	 * know that we "own" the pipe.  If we delete before locking,
	 * there's a race where after we opened the pipe, a different
	 * reader also opened, deleted, and locked the file, and a new
	 * writer created a new pipe; in that case, we'd be deleting the
	 * wrong pipe.
	 */
	logs("Remove FIFO");
	remove(FIFO);
	while ((var = read(fifo, buf, BUFFERSIZE)) > 0) {
		printf("[%s](pid %d) DEBUG: Passed %s %d : reader reads record: %s", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, buf);
		/* No need to sleep; we'll consume input as it becomes available. */
	}

	close(fifo);
	logs("EOF reader");
	exit(0);

}

/**
 * Klient named pipe
 *
 * write to pipe
 *
 * @param argc
 * @param argv
 * @return
 */
int wrfifo(pid_t pid) {
	// time structs
	time_t rawtime;
	struct tm * timeinfo;

	int len, i;
	char buf[PIPE_BUF];
	int fd;
	int communicates = 0;

//	if ((unlink(FIFO)) == -1) {
//		logs("Error unlink FIFO")
//	} else {
//		logs("unlink fifo");
//	}

	if ((mkfifo(FIFO, FIFO_PERMS) == -1) && (errno != EEXIST)) {
		logs("Server failed to create a FIFO");
		return (1);
	} else if (errno == ENOENT) {
		printf("[%s](pid %d) DEBUG: Passed %s %d : No such file or directory - mkfifo errno: %d\n", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, errno);
	} else if (errno == EEXIST) {
		printf("[%s](pid %d) DEBUG: Passed %s %d : mkfifo exist: %d\n", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, errno);
	} else {
		printf("[%s](pid %d) DEBUG: Passed %s %d : No such file or directory - mkfifo errno: %d\n", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, errno);
	}

	if ((fd = open(FIFO, O_WRONLY)) == -1) {
		logs("Client failed to open log fifo for writing");
		return (1);
	} else {
		logs("pipe opened to read-write");
	}

	/**
	 * write some text to pipe
	 */
	for (i = 0; i < 10; i++) {
		sleep(1);
		//logs("time")
		time(&rawtime);
		timeinfo = localtime(&rawtime);
		sprintf(buf, "#%d test PID: %d: text -> %s", communicates++, (int) getpid(), asctime(timeinfo));
		len = strlen(buf);
		if (write(fd, buf, len) != len) {
			logs("Client failed to write");
			return (1);
		} else {
			printf("[%s](pid %d) DEBUG: Passed %s %d : client succesed write to pipe: %s", __TIME__, (int) getpid(), __FUNCTION__, __LINE__, buf);
		}
	}
	/* Wait for the child process to finish. */
	waitpid(pid, NULL, 0);
	sleep(1);
	logs("close fd");
	close(fd);
	return (0);
}

/**
 * main
 *
 * @return
 */
int main(int argc, char *argv[]) {
	pid_t pid;
	int i;

	/**
	 * analiza lini komend
	 *
	 */
	int opt = 0;
	char *in_fname = NULL;
	char *out_fname = NULL;

	/**
	 * funkcje programu
	 */
	while ((opt = getopt(argc, argv, "rwh")) != -1) {
		switch (opt) {
		case 'r':
			in_fname = optarg;
			printf("\nInput option value=%s set program read from FIFO", in_fname);
			rdfifo();
			exit(0);
			break;
		case 'w':
			out_fname = optarg;
			printf("\nInput option value=%s set program to write to FIFO", out_fname);
			wrfifo(pid);
			exit(0);
			break;
		case '?':
		case 'help':
		case 'h':
		default:
			printf("\nProgram FIFO\n");
			printf("------------\n");
			printf("Program bez argumentów tworzy named pipe a w procesie potomnym zapisuje do niego dane.\n");
			printf("Program mozna wywołać z argumentami tak aby działał jako odczyt (r) z pipe lub zapis do pipe (w).\n");
			printf("Zapisywane są do pipe couner, PID i curenttime.\n\n");
			printf("Usage: %s [-r] [-w]\n\n", argv[0]);

			exit(0);
			break;
		}
	}

	logs("start program");

	pid = fork();

	/* proces potomny */
	if (pid == (pid_t) 0) { /* brak obsługi błędów */
		/**
		 * Odczytywanie
		 */
		for (i = 0; i < 3; i++) {
			rdfifo();
			sleep(1);
		}
	}
	/* proces macierzysty */
	else {
		for (i = 0; i < 5; i++) {
			wrfifo(pid);

		}
	}
	logs("end main");
	return (0);
}

Zrzut z działania

[23:30:20](pid 17400) DEBUG: Passed rdfifo 73 - while1

karol@carlo:~/eclipse-workspaces/unx_sys_programming/Debug$ ./unx_sys_programming -w

Input option value=(null) set program to write to FIFO

[23:30:20](pid 17411) DEBUG: Passed wrfifo 148 : mkfifo exist: 17
[23:30:20](pid 17411) DEBUG: Passed wrfifo 157 - pipe opened to read-write
[23:30:20](pid 17400) DEBUG: Passed rdfifo 104 - Remove FIFO
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #0 test PID: 17411: text -> Thu Jan 28 23:36:02 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #0 test PID: 17411: text -> Thu Jan 28 23:36:02 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #1 test PID: 17411: text -> Thu Jan 28 23:36:03 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #1 test PID: 17411: text -> Thu Jan 28 23:36:03 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #2 test PID: 17411: text -> Thu Jan 28 23:36:04 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #2 test PID: 17411: text -> Thu Jan 28 23:36:04 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #3 test PID: 17411: text -> Thu Jan 28 23:36:05 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #3 test PID: 17411: text -> Thu Jan 28 23:36:05 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #4 test PID: 17411: text -> Thu Jan 28 23:36:06 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #4 test PID: 17411: text -> Thu Jan 28 23:36:06 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #5 test PID: 17411: text -> Thu Jan 28 23:36:07 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #5 test PID: 17411: text -> Thu Jan 28 23:36:07 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #6 test PID: 17411: text -> Thu Jan 28 23:36:08 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #6 test PID: 17411: text -> Thu Jan 28 23:36:08 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #7 test PID: 17411: text -> Thu Jan 28 23:36:09 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #7 test PID: 17411: text -> Thu Jan 28 23:36:09 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #8 test PID: 17411: text -> Thu Jan 28 23:36:10 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #8 test PID: 17411: text -> Thu Jan 28 23:36:10 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 174 : client succesed write to pipe: #9 test PID: 17411: text -> Thu Jan 28 23:36:11 2016
[23:30:20](pid 17400) DEBUG: Passed rdfifo 107 : reader reads record: #9 test PID: 17411: text -> Thu Jan 28 23:36:11 2016
[23:30:20](pid 17411) DEBUG: Passed wrfifo 180 - close fd
[23:30:20](pid 17400) DEBUG: Passed rdfifo 112 - EOF reader

[10]   Done                    ./unx_sys_programming -r

bash:~/eclipse-workspaces/unx_sys_programming/Debug$ ./unx_sys_programming -h

Program FIFO
Program bez argumentów tworzy named pipe a w procesie potomnym zapisuje do niego dane.
Program mozna wywołać z argumentami tak aby działał jako odczyt (r) z pipe lub zapis do pipe (w).
Zapisywane są do pipe couner, PID i curenttime.

Usage: ./unx_sys_programming [-r] [-w]

Example solution 2 (draft)

/**
 * Zadania
 * -------
 * z1: Napisz program, który pokazuje, które atrybuty procesu macierzystego są dziedziczone przez proces potomny  uruchomiony za pomocą funkcji fork(), które zaś otrzymują nową wartość.
 * z2: Napisz program, który pokazuje, które atrybuty procesu są zachowane przez proces po wykonaniu funkcji exec().
 * z3: Napisz program, który wyświetla identyfikator procesu (PID) i nazwę związanego z nim polecenia dla wszystkich procesów uruchomionych przez użytkownika podanego w wierszu wywołania programu. Wskazówka: informacje te można uzyskać przeglądając katalog /proc z plików (interesują nas katalogi, których właścicielem jest dany  użytkownik) i pliki /proc/PID/status
 *
 * Każdy proces charakteryzuje się pewnymi atrybutami. Należą do nich:
 * Identyfikator procesu PID
 * Identyfikator procesu macierzystego PPID
 * Rzeczywisty identyfikator właściciela procesu
 * Rzeczywisty identyfikator grupy procesu
 * Efektywny identyfikator właściciela procesu
 * Efektywny identyfikator grupy procesu
 * Katalog bieżący i katalog główny
 * Maska tworzenia pliku
 * Identyfikator sesji
 * Terminal sterujący
 * Deskryptory otwartych plików
 * Ustalenia dotyczące obsługi sygnałów
 * Ustawienia zmiennych środowiskowych
 * Ograniczenia zasobów
 *
 *
 * Potomek dziedziczy z procesu potomnego wiele własności:
 rzeczywisty identyfikator użytkownika, rzeczywisty identyfikator grupy, obowiązujący identyfikator użytkownika, obowiązujący identyfikator grupy,
 identyfikatory dodatkowych grup,
 identyfikator sesji,
 terminal sterujący,
 sygnalizator ustanowienia identyfikatora użytkownika oraz sygnalizator ustanowienia identyfikatora grupy,
 deskryptory otwartych plików (są kopiowane)
 bieżący katalog roboczy,
 katalog główny,
 maskę tworzenia plików,
 maskę sygnałów oraz dyspozycje obsługi sygnałów,
 sygnalizator zamykania przy wywołaniu funkcji exec (close-on-exec) dla wszystkich otwartych deskryptorów plików,
 środowisko,
 przyłączone segmenty pamięci wspólnej,
 ograniczenia zasobów systemowych.
 Są jednak pewne różnice między procesem macierzystym a potomnym:
 wartość powrotu z funkcji fork,
 różne identyfikatory procesów,
 inne identyfikatory procesów macierzystych - w procesie potomnym jest to identyfikator procesu macierzystego; w procesie macierzystym identyfikator procesu macierzystego nie zmienia się,
 w procesie potomnym wartości tms_utime, tms_cutime i tms_ustime są równe 0,
 potomek nie dziedziczy rygli plików, ustalonych w procesie macierzystym,
 w procesie potomnym są zerowane wszystkie zaległe alarmy,
 w procesie potomnym jest zerowany zbiór zaległych sygnałów.
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

extern char** environ;
char *prt_parent;

int glob = 1; 			// zewnętrzna zmienna

/* Prints the environment, one environment variable to a line, of the
 process given by PID. */
char *print_process_environment(pid_t pid) {
	int fd;
	char filename[24];
	char environment[8192];
	size_t length;
	char* next_var;
	/* Generate the name of the environ file for the process. */
	snprintf(filename, sizeof(filename), "/proc/%d/environ", (int) pid);
	/* Read the contents of the file. */
	fd = open(filename, O_RDONLY);
	length = sizeof(environ);
	printf("Size of environ: %d\n", length);
	close(fd);
	/* read does not NUL-terminate the buffer, so do it here. */
	environment[length] = '\0';
	/* Loop over variables. Variables are separated by NULs. */
	next_var = environment;
	while (next_var < environment + length) {
		/* Print the variable. Each is NUL-terminated, so just treat it
		 like an ordinary string. */
		printf(">> %s\n", next_var);
		/* Advance to the next variable. Since each variable is
		 NUL-terminated, strlen counts the length of the next variable,
		 not the entire variable list. */
		next_var += strlen(next_var) + 1;
	}
	return (environment);
}

//int main(int argc, char* argv[]) {
//pid_t pid = (pid_t) atoi (argv[1]);
//print_process_environment (pid);
///return 0;
//}

int main1(int argc, char **argv) {
	int var = 100; 		        // zmienna automatyczna na stows
	char **env = environ;		// środowisko parent
	// zapamiętanie environ w tablicy

	printf("PROGRAM Z1\n\n");
	printf("Zmienne srodowiskowe parent: ----------------------------\n");
	while (*env) {
		printf("%s\n", *env++);
	}

	printf("---------------------------------------------------------\n");

	//for (int i = 0; *env != NULL && gets(env[i]); i++)
	//	prt_parent[i] = env[i];

	pid_t pid = fork();

	if (pid == 0) {
		// child process
		glob++;
		var++;
		printf("child process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
				glob, var);

		/**
		 * wy swietlenie zmiennych środowiskowych różnych od parent
		 */
		printf("Zmienne srodowiskowe child różne od parent:\n");
		char environment_1[8192];
		char * prt_env = &environment_1;
		prt_env = print_process_environment(pid);
		char **env_child = environ;
		printf("Size of *char: %d\n", sizeof(environ));

		while (*env_child) {
			printf("compare - %s %d\n", *env_child, strcmp(*env_child++, *env++));
			//printf("%s -----\n", *env2++);
			//if (strcmp(*env2, ++*env) == 0) {
			//
			//} else {
			//printf("%s jest takie samo\n", *env2);
			//}
			//*env_child++;
			//*env++;
		}
		printf("-------------------- x --------------------\n");

	} else if (pid > 0) {
		// parent process
		printf("parent process: pid %d, ppid %d, getuid %d, geteuid %d, getgid %d, glob = %d, var = %d\n", getpid(), getppid(), getuid(), geteuid(), getgid(),
				glob, var);
	} else {
		// fork failed
		printf("fork() failed!\n");
		return (1);
	}

	printf("-- end of program pid %d\n", getpid());

	return (0);
}

Using fork() in C/C++ – a minimum working example

In a C or C++ program, fork() can be used to create a new process, known as a child process. This child is initially a copy of the the parent, but can be used to run a different branch of the program or even execute a completely different program. After forking, child and parent processes run in parallel. Any variables local to the parent process will have been copied for the child process, so updating a variable in one process will not affect the other.

Consider the following example program:

#include <stdio .h>
#include <unistd .h>
#include <stdlib .h>
#include <string .h>
#include <sys /types.h>
#include </sys><sys /resource.h>
#include <fcntl .h>
#include <sys /stat.h>
#include </sys><sys /types.h>
#include <unistd .h>
int main(int argc, char **argv)
{
printf("--beginning of program\n");
 
int counter = 0;
pid_t pid = fork();
 
if (pid == 0)
{
// child process
int i = 0;
for (; i < 5; ++i) { printf("child process: counter=%d\n", ++counter); } } else if (pid > 0)
{
// parent process
int j = 0;
for (; j < 5; ++j)
{
printf("parent process: counter=%d\n", ++counter);
}
}
else
{
// fork failed
printf("fork() failed!\n");
return 1;
}
 
printf("--end of program--\n");
 
return 0;
}

This program declares a counter variable, set to zero, before fork()ing. After the fork call, we have two processes running in parallel, both incrementing their own version of counter. Each process will run to completion and exit. Because the processes run in parallel, we have no way of knowing which will finish first. Running this program will print something similar to what is shown below, though results may vary from one run to the next.

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

Automat komórkowy w C | Cellular automaton (CA) in C

Cellular automata and Moore neighborhood

Cellular automaton (CA) is by definition a periodic grid of cells, where in each cell sits a finite automaton, and a set of (identical) rules for every such automaton describing to which state it switches on a next moment of discrete time ti+1, depending of its own state and states of all its neighbors on a current moment of time ti. For now, we will be interested in 2d, rectangular CA, and a neighborhood which includes 8 neighbors of the cell. This is what is called the Moore neighborhood, because it was invented by Edward Moore.

Rules Brain

http://zvold.blogspot.com/2010/01/conways-life-and-brians-brain-cellular.html

  • Each cell has three possible states: passive, active, and semi-active.
  • If a cell is active, it goes to semi-active state on the next step
  • If a cell is semi-active, it becomes passive on the next step
  • If a cell is passive, it becomes active if and only if it has exactly 2 active neighbors

Materials

  • http://meil.pw.edu.pl/za/ZA/Dydaktyka/Informatyka-1
  • https://en.wikipedia.org/wiki/Cellular_automaton
  • git clone :snippets/karol-preiskorn/E8e4L/brians-brain.git

Source

/**
* Brian's Brain
*
* Rules:
* -------
* Each cell has three possible states: passive, active, and semi-active.
* If a cell is active, it goes to semi-active state on the next step
* If a cell is semi-active, it becomes passive on the next step
* If a cell is passive, it becomes active if and only if it has exactly 2 active neighbors
*
**/
#include 
#include 

#include 
#include 

 

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑