C process and interprocess communication in Linux Environment

Basic concept of process:

1. Processes and procedures

A program is an executable file stored on disk. The program is loaded into memory and starts running.

When a program is loaded multiple times, multiple processes are generated

A process is an active computer program

2. Classification of processes

Processes are generally divided into three types: interactive process, batch process and daemon process

When the system is in the active state, it is automatically started by the daemon process in the background

3. View process

Simple mode ps displays the process information of the current user's control terminal

List mode ps auxw displays all process details

a processes with control terminals for all users

x process without control terminal

u displays the details of the process

w is displayed with a larger column width

Owner of USER process

PID process number

%CPU utilization

%MEM kernel usage

Bytes used by VSZ virtual memory

Bytes used by RSS physical memory

TYY terminal equipment number? Indicates that there is no terminal control device

Status of STAT process

O ready, waiting to be dispatched

R is running, the Linux system does not have 0, and ready is also represented by R

S sleep that can be awakened, such as system interruption, obtaining resources and receiving signals, can wake it into running state

D sleep that cannot be awakened can only be awakened by the system

T suspended state: after receiving SIGSTOP signal, it enters the suspended state, and after receiving SIGCONT signal, it enters the running state

W waiting for memory paging (abandoned after 2.6 kernel)

Z ombie state

X death status

< high priority

N low priority

l multithreaded process

Leader of s process

L memory locked into memory

+ process group in background

The time when the START process started

TIME

COMMAND command to start the process

4. Parent process, child process, orphan process and zombie process

A process can be created by another process. The creator is called the parent process and the creator is called the child process. After the child process is started by the parent process, it will run at the same time under the call of the operating system

When the child process ends before the parent process, the child process will send a SIGCHLD signal to the parent process. At this time, the parent process should recycle the relevant resources of the child process. If not, the child process will become a zombie process

Zombie process: the process has died, but its parent process does not immediately recover its related resources, so the process enters the zombie state

Orphan process: the parent process ends before the child process, and the child process becomes an orphan process. At this time, the orphan process will be adopted by the orphanage (init daemon), and init is the parent process of the orphan process

5. Process identifier

Each process has a unique representation of a non negative integer representation, that is, its process ID/PID

The process ID is unique at any time, but it can be reused. Once the process is completed, its PID will be recycled by the system and can be reassigned to other newly created processes for use after a period of time (delayed reuse)

pid_t getpid(void);
Function: get the process of the current process ID

pid_t getppid(void);
Function: get the parent process of the current process ID

init Process of ID Always 1

Create process:

​ int system(const char *command);

Function: execute an executable file, which creates a child process

Return value: returns after the child process ends

The implementation of this function calls the fork and waitpid functions. In fact, it is equivalent to creating a sub process, which loads the executable command

​ pid_t fork(void);

Function: create sub process

Return value: return twice in a call. The child process returns 0. The parent process returns the ID of the child process. When the number of processes exceeds the system limit, the process creation fails and returns - 1

The child process created through fork will copy the parent process (data segment, bss segment, heap, stack, IO buffer) and other data areas, share the code segment with the parent process, and the child process will inherit the information processing method of the parent process

After the function is called, the parent and child processes run independently. It is uncertain who returns first, but you can determine which process executes first through sleep

​ for(;😉

​ {

​ fork(); // Will run out of resources

​ }

The parent process can enter different branches and execute different codes according to different return values

Creating a child process through fork can share the file descriptor of the parent process

Different ordinary processes cannot share file descriptors with the same value

pid_t vfork(void)

Function: create sub processes by loading executable files

Return value: the child process returns 0, and the parent process returns the PID of the child process

The child process returns first. At this time, the child process is not created successfully. You need to load an executable file to replace all the resources of the current child process. The child process that completes the replacement is created successfully, and the parent process can return

#include <stdio.h>
#include <unistd.h>

int main(int argc,const char* argv[])
{
	printf(".%d\n",getpid());
	pid_t pid = fork();
	if(0 == pid)
	{
		printf("I am a subprocess%u My parent process is %u\n",getpid(),getppid());	
		pause();
	}
	else
	{
		printf("I am the parent process %u,My subprocess is %u\n",getpid(),pid);	
		pause();
	}
}

Use the exec system function to load the executable file:

int execl(const char *path, const char *arg, ...);
path: Path to executable
arg: Generally, the first parameter on the command line is the name of the executable file. At least one parameter is NULL ending

int execlp(const char *file, const char *arg, ...);
file: The name of the executable file will be changed according to the environment variable PATH To find the executable

int execle(const char *path, const char *arg,
                  ..., char * const envp[]);
envp: Environment variable table. The parent process can pass the environment variable table to the child process when loading the child process, so that the parent and child processes share one environment variable table

int execv(const char *path, char *const argv[]);
argv: Pointer array, which is composed of strings passed to child processes to NULL ending

int execvp(const char *file, char *const argv[]);

int execvpe(const char *file, char *const argv[],
                  char *const envp[]);

Note: exec series functions will not return normally. When the loading sub process fails to load the executable file, it will return - 1

The child process created with exec series functions will not inherit the signal processing function of the parent process, but can inherit the signal mask of the parent process

Normal exit of process:

1. Execute return n in the main function, and the return value can be received by its parent process

2. The exit function is called, which is a standard library function

​ void exit(int status);

Function: calling this function at any time can end the process

Status: end status code, which has the same effect as the return value in the return function

Note: this function does not return

Before the process exits

int atexit(void (*function)(void));
Function: register the function to be executed before the end of a process

int on_exit(void (*function)(int , void *), void *arg);
Function: register the function to be executed before the end of a process
int: return Value or exit Parameters of function
arg: Will be automatically passed to at the end of the process function function

call exit What will happen:
1,Call first and pass in advance atexit/on_exit If all registered functions are registered, the execution order is opposite to the registration order
2,Flush and close the standard in the open state IO flow
3,The implementation of this function calls_exit/_Exit	

3. Call_ exit / _Exit function

void _exit(int status);
Function: end the process, provided by the system

void _Exit(int status);
Function: end the process, provided by the standard library
	1,Their parameters will be obtained by the parent process
	2,All open file descriptors will be closed before the process ends(open)
	3,Send to parent process SIGCHLD signal
	4,The function also does not return

4. The last thread of the process executes the return statement

5. The last thread of the process executes pthread_exit function

Abnormal termination of process:

1. The process calls the abort function and generates the SIGABRT signal

2. The process can accept some signals, which can be sent by other processes, sent by itself, or caused by its own error

3. The last thread of the process received a cancel operation and responded to it

These three end methods cause the parent process to be unable to obtain the end status code, all of which are called abnormal termination

Note: no matter how the process ends, it will execute the same piece of code, close all open file descriptors and free all memory

whether

Recycling of child processes:

For any ending method, the parent process is expected to know how the child process ends and the ending status code through the wait and waitpid functions

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
Function: wait for the end of the sub process and obtain the end status code
 Return value: child process PID
	1,If all child processes are running, the function will block
	2,If any child process ends, it will immediately return the end status code and PID
	3,If there are no child processes, return immediately-1
	
	WIFEXITED(status)	Judge whether the subprocess ends normally. If so, return true
	WEXITSTATUS(status)	If the subprocess ends normally, you can get the correct end status code, only															Can get the lower eight bits
	WIFSIGNALED(status)	Judge whether the subprocess ends normally. If so, return true
	WTERMSIG(status)	Judge whether the subprocess is abnormally terminated, and you can obtain the signal code leading to the abnormal termination
	
be careful:
	because wait The function may be blocked, so it is not suitable to call it in the business logic of the parent process. Therefore, you can use SIGCHID Signal processing function, which is called in the processing function wait Function. Note that you can get the status of the ending child process without affecting the normal business logic of the parent process
	
pid_t waitpid(pid_t pid, int *status, int options);
Function: specifies to recycle one or more processes
pid: 
	< -1	Waiting to belong abs(pid)The process in the process group with the number of ends
	-1		Wait for the end of any child process. The function is equivalent to wait
	0		Wait for any process in the same group to end
	>0		wait for pid The process ends
status: Process end status code, and wait Equivalence of
options: 
	0			Blocking mode, equal to wait
	WNOHANG		Non blocking mode, if no child process ends, return immediately
	WUNTRACED	If a process is in a suspended state, the status code of the process is returned
	WCONTINUED	If a process changes from suspended state to continue running, the status code of the process is returned
	
	WIFSTOPPED(status)	Judge whether the process is in a suspended state. If yes, it returns true
	WSTOPSIG(status)	Gets the signal that caused the process to pause
	WIFCONTINUED(STATUS)Judge whether the process changes from suspended state to running state. If yes, it returns true
	

Exercise: use today's knowledge to implement a system function

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int _system(const char* command)
{
	pid_t pid = vfork();
	if(0 == pid)
	{
		return execlp(command,command,NULL);
	}
	else
	{
		int status = 0;
		waitpid(pid,&status,0);
		return status;
	}
}

int main(int argc,const char* argv[],char** environ)
{
	_system("clear");
	printf("-----------");
}

Interprocess communication:

Basic concepts:

What is interprocess communication:

It refers to the process of data interaction between two or more processes, because processes are independent of each other. In order to make multiple processes work together, they must interact with each other

Classification of interprocess communication: (required)

Simple interprocess communication: signals, files, environment variables, command line parameters

Traditional way of interprocess communication: pipeline file

XSI interprocess communication: shared memory, message queue, semaphore

Network interprocess communication: Socket socket local Socket file network TCP/IP

Traditional interprocess communication:

Pipeline is the oldest way of inter process communication in UNIX, which means that all systems support it. In the early days, the pipeline was half duplex, and now some systems have full duplex (but it should also be assumed that the pipeline is half duplex)

A pipe is a special file. Its data flows in the file and will disappear after reading. If there is no data in the file to read, it will be blocked

Famous pipeline:

Communication based on pipeline file with file name

Programming model

Process A process B

Create pipe

Open pipe open pipe

Write data read data

Close the pipe close the pipe

Delete pipe

To create a pipe file:
1,command mkfifo file
2,Function:
	int mkfifo(const char *pathname, mode_t mode);
	Functions: creating pipe files
	pathname: Pipeline file path
	mode: Pipeline file permissions
3,Standard library function
	FILE* popen(const char *command, const char *type);
	Function: open or create pipe files
	command: Executable file name
	type: 
		r		The file pointer links to the standard output of the executable
		w		The file pointer links to the standard input of the executable file
		
	int pclose(FILE *stream);
	Function: close pipe file
	Note: special functions for closing pipeline files must not be associated with fclose Mixed use
//	A
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc,const char* argv[])
{
	int fd[2] ={};
	//	Gets the fd array of anonymous pipes
	if(pipe(fd))
	{
		perror("pipe");
		return -1;
	}

	//	Create child process
	if(fork())
	{
		// Parent process 	 Responsible for writing and closing reading
		close(fd[0]);
		for(;;)
		{
			char buf[256] = {};
			printf(">>>");
			scanf("%s",buf);
			write(fd[1],buf,strlen(buf));
			if(0 == strcmp("quit",buf))
			{
				printf("End of communication\n");
				usleep(5000);
				break;
			}
			usleep(5000);
		}
		close(fd[1]);
	}
	else
	{
		//	The subprocess is responsible for reading and writing
		close(fd[1]);
		for(;;)
		{
			char buf[256] = {};
			read(fd[0],buf,sizeof(buf));
			printf("read:%s\n",buf);
			if(0 == strcmp(buf,"quit"))
			{
				printf("End of communication\n");
				break;
			}
		}
		close(fd[0]);
	}
}
//	B
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main(int argc,const char* argv[])
{
	//Open pipe file
	int fd = open("fifo",O_RDONLY);
	if(0 > fd)
	{
		perror("open");
		return -1;
	}
	
	//Read data
	for(;;)
	{
		char buf[256] = {};
		read(fd,buf,sizeof(buf));
		printf("read:%s\n",buf);
		if(0 == strcmp(buf,"quit"))
		{
			printf("End of communication!\n");
			break;
		}
	}
	//Close pipe file
	close(fd);
}

Anonymous pipeline:

Note: it is only suitable for use between parent and child processes created through the fork function

Programming model

Parent process and child process

Create and get a pair of fd

Create a child process and copy a pair of fd

Turn off read and write

Write data read data

Turn off write and turn off read

int pipe(int pipefd[2]);
Function: create an anonymous pipeline file,
pipefd: For storing pipe files fd Array of
	pipefd[0]:For reading
	pipefd[1]:For writing
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc,const char* argv[])
{
	int fd[2] ={};
	//	Gets the fd array of anonymous pipes
	if(pipe(fd))
	{
		perror("pipe");
		return -1;
	}

	//	Create child process
	if(fork())
	{
		// Parent process 	 Responsible for writing and closing reading
		close(fd[0]);
		for(;;)
		{
			char buf[256] = {};
			printf(">>>");
			scanf("%s",buf);
			write(fd[1],buf,strlen(buf));
			if(0 == strcmp("quit",buf))
			{
				printf("End of communication\n");
				usleep(5000);
				break;
			}
			usleep(5000);
		}
		close(fd[1]);
	}
	else
	{
		//	The subprocess is responsible for reading and writing
		close(fd[1]);
		for(;;)
		{
			char buf[256] = {};
			read(fd[0],buf,sizeof(buf));
			printf("read:%s\n",buf);
			if(0 == strcmp(buf,"quit"))
			{
				printf("End of communication\n");
				break;
			}
		}
		close(fd[0]);
	}
}

XSI interprocess communication:

System interface for interprocess communication executed by X/open company

XSI interprocess communication requires the help of the system kernel, and the kernel object needs to be created. The kernel object is returned to the user in the form of an integer, which is equivalent to a file descriptor, also known as IPC identifier

The file name is required for the creation and opening of files, and the IPC key value (integer) is also required for the creation of IPC kernel objects. It must be ensured that the IPC key value is unique

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
Function: calculate a unique IPC Key value
pathname: The project path is not calculated by characters, but by the location of the path. If the provided path is a false path, it may be calculated by accounting IPC Key value
proj_id: Item No
 Return value: calculated IPC Key value
    

Shared memory:

Basic features:

Two or more processes share a piece of memory managed and maintained by the kernel, which can be mapped with the virtual memory space of the process

Advantages: it does not need to copy information and is the fastest IPC mechanism
Disadvantages: synchronous access needs to be considered

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
Function: create\Get shared memory
key: Unique information provided by the process IPC Key value
size: The size of shared memory. When obtaining shared memory, this parameter is meaningless and is generally set to 0
shmflg: 
	IPC_CREAT	Create shared memory
	IPC_EXCL	Error returned when shared memory already exists
	Assign 0 when getting
	mode_flags: Permissions are required to create shared memory
 Return value: IPC Identifier, error return-1

void *shmat(int shmid, const void *shmaddr, int shmflg);
Function: mapping between virtual memory and shared memory
shmid: IPC Identifier, shmget Return value of
shmaddr: The virtual memory address you want to map. Here you are NULL The system will operate automatically
shmflg: 
	SHM_RDONLY: Access shared memory as read-only
 Return value: the first address of the virtual memory mapped with the shared memory. Failure is returned(void *) -1

int sgmdt(const void *shmaddr);
Function: unmap
shmaddr: Mapped virtual memory address

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
Function: delete/Control shared memory
shmid: IPC identifier 
cmd: 
	IPC_STAT	Get shared memory properties	be buf It is an output parameter
	IPC_SET		Set shared memory properties	be buf It is an input parameter
	IPC_RMID	Delete shared memory		  NULL
	struct shmid_ds {
           struct ipc_perm shm_perm;    //Information about the owner
           size_t          shm_segsz;   //Shared memory bytes
           time_t          shm_atime;   //Last mapping time
           time_t          shm_dtime;   //Last unmapping time
           time_t          shm_ctime;   //Last change time
           pid_t           shm_cpid;    //Creator process number
           pid_t           shm_lpid;   	//Last mapped \ unmapped process number
           shmatt_t        shm_nattch; 	//Current mapping times
           ...
       };
	struct ipc_perm {
               key_t          __key;  //Create PIC key value of shared memory  
               uid_t          uid;    //User ID currently using shared memory
               gid_t          gid;    //User group ID currently using shared memory
               uid_t          cuid;   //User ID to create shared memory
               gid_t          cgid;   //User group ID to create shared memory
               unsigned short mode;   //Shared memory permissions
               unsigned short __seq;  //Serial number of shared memory
       };

Programming model

Process A process B

Create shared memory get shared memory

Map shared memory map shared memory

Notify read after writing data read after receiving read notification

Read data after receiving read notification and notify read after writing data

Unmapping unmapping

Delete shared memory

//	Process A
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

int shmid;
char* shm;

//After receiving the read message, the signal processing function is responsible for reading data from the shared memory
void sigrtmin(int num)
{
	//	Receive read messages and read data
	printf("read:%s\n",shm);
	if(0 == strcmp("quit",shm))
	{
		printf("End of communication\n");
		//Unmap
		if(shmdt(shm))
		{
			perror("shmdt");
			exit(-1);
		}
		usleep(1000);//Wait for the opposite process to unmap
		//Delete shared memory
		if(shmctl(shmid,IPC_RMID,NULL))
		{
			perror("shmctl");
			exit(-1);
		}
	}
}

int main(int argc,const char* argv[])
{
	//	Register signal processing function
	signal(SIGRTMIN,sigrtmin);
	printf("I am the process%u\n",getpid());

	pid_t pid = 0;
	printf("Please enter the process of communicating with me PID:");
	scanf("%u",&pid);

	//	Create shared memory
	shmid = shmget(ftok(".",110),4096,IPC_CREAT|0644);
	if(0 > shmid)
	{
		perror("shmget");
		return -1;
	}

	//	Map shared memory
	shm = shmat(shmid,NULL,0);
	if(shm == (void*)-1)
	{
		perror("shmat");
		return -1;
	}

	//	Write data and notify other processes
	for(;;)
	{
		printf(">>>");
		scanf("%s",shm);
		kill(pid,SIGRTMIN);
		if(0 == strcmp(shm,"quit"))
		{
			printf("End of communication\n");
			break;
		}

	}
	//	Unmap
	if(shmdt(shm))
	{
		perror("shmdt");
		return -1;
	}
	
	usleep(1000);//Wait for the opposite process to unmap

	//Delete shared memory
	if(shmctl(shmid,IPC_RMID,NULL))
	{
		perror("shmctl");
		return -1;
	}

}
//	Process B
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

char* shm;

//After receiving the read message, the signal processing function is responsible for reading data from the shared memory
void sigrtmin(int num)
{
	//	Receive read messages and read data
	printf("read:%s\n",shm);
	if(0 == strcmp("quit",shm))
	{
		printf("End of communication\n");
		//Unmap
		if(shmdt(shm))
		{
			perror("shmdt");
			exit(-1);
		}
		exit(0);//quti has been received. You need to end the whole program
	}
}

int main(int argc,const char* argv[])
{
	//	Register signal processing function
	signal(SIGRTMIN,sigrtmin);
	printf("I am the process%u\n",getpid());

	pid_t pid = 0;
	printf("Please enter the process of communicating with me PID:");
	scanf("%u",&pid);

	//	Get shared memory
	int shmid = shmget(ftok(".",110),0,0);
	if(0 > shmid)
	{
		perror("shmget");
		return -1;
	}

	//	Map shared memory
	shm = shmat(shmid,NULL,0);
	if(shm == (void*)-1)
	{
		perror("shmat");
		return -1;
	}

	//	Write data and notify other processes
	for(;;)
	{
		printf(">>>");
		scanf("%s",shm);
		kill(pid,SIGRTMIN);
		if(0 == strcmp(shm,"quit"))
		{
			printf("End of communication\n");
			break;
		}

	}
	//	Unmap
	if(shmdt(shm))
	{
		perror("shmdt");
		return -1;
	}
}

Message queue:

Basic features: it is a data linked list managed and maintained by the kernel, which sends and receives data through message types.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
Function: create\Get message queue
key: IPC Key value
msgflg: 
	IPC_CREAT	Create message queue
	IPC_EXCL	If the message queue already exists, an error is returned
	If get message queue	Directly to 0
	If you are creating a message queue, remember to provide permissions mode
 Return value: returned successfully IPC Identifier, error return-1

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
Function: send data to message list
msqid: IPC identifier 
msgp: The first address of the message to send
 		struct msgbuf {
               long mtype;       //	Message type
               char mtext[n];    //	data
         	  };
msgsz: The number of bytes of data, excluding the message type
msgfl: 
	Blocking general write 0
	IPC_NOWAIT	When the message queue is full, do not wait to return immediately
    
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
Function: read data from message queue
msqid: IPC identifier 
msgp: First address of stored data
msgsz: The maximum number of bytes of data in the structure
msgtyp: Message type
	0	Read the first message in the message queue
	>0	Read the message type in the message queue equal to msgtyp News of
	<0	Read message type is less than abs(msgtyp)Message, if more than one, the smallest message is read
msgflg: 
	IPC_NOWAIT	When there is no matching message type in the message queue, it returns immediately
	MSG_EXCEPT	If msgtyp>0,The first message type read is not msgtyp News of
	MSG_NOERROR	If this flag is included, read msgsz Bytes. If this flag is not included, the actual length of the message>msgsz,An error is returned without reading the data.
Return value: the number of bytes successfully read

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
Function: delete\Get properties of message queue
msqid: IPC identifier 
cmd: 
	IPC_STAT	Get properties of information queue
	IPC_SET		Set properties of message queue
	IPC_RMID	Delete message queue
buf: 
 		struct msqid_ds {
               struct ipc_perm msg_perm;   //	Owner information
               time_t          msg_stime;    //	Last sending time
               time_t          msg_rtime;    //	Last receiving time
               time_t          msg_ctime;    //	Last modification time
               unsigned long   __msg_cbytes; //	Bytes of the current message queue
               msgqnum_t       msg_qnum;   	 //	Number of messages in the current message queue
               msglen_t        msg_qbytes;   //	The maximum number of bytes of a message in the queue
               pid_t           msg_lspid;    //	Last sender's PID
               pid_t           msg_lrpid;    //	PID of last receiver
           };

Programming model

Process A process B

Create message queue get message queue

Send message receive message

Receive message send message

Delete message queue

//	Process A
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "messgeage.h"

int main(int argc,const char* argv[])
{
	//	Create message queue
	int msgid = msgget(ftok(".",120),IPC_CREAT|0644);
	if(0 > msgid)
	{
		perror("msgget");
		return -1;
	}

	Msg msg = {};
	for(;;)
	{
		msg.type = 5;
		printf(">>>");
		scanf("%s",msg.data);

		//send message
		if(msgsnd(msgid,&msg,strlen(msg.data)+1,0))
		{
			perror("msgsnd");
			break;
		}
		if(0 == strcmp("quit",msg.data)) break;


		//receive messages
		if(0 == msgrcv(msgid,&msg,MESMAX,6,0))
		{
			perror("msgrcv");
			break;
		}
		printf("recv:%s\n",msg.data);
		if(0 == strcmp("quit",msg.data)) break;
	}
	
	printf("End of communication!\n");

	usleep(1000);

	//	Delete message queue
	if(msgctl(msgid,IPC_RMID,NULL))
	{
		perror("msgctl");
		return -1;
	}
	return 0;
}
//	Process B
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include "messgeage.h"

int main(int argc,const char* argv[])
{
	//	Get message queue
	int msgid = msgget(ftok(".",120),0);
	if(0 > msgid)
	{
		perror("msgget");
		return -1;
	}

	Msg msg = {};
	for(;;)
	{
		//receive messages
		if(0 == msgrcv(msgid,&msg,MESMAX,5,0))
		{
			perror("msgrcv");
			break;
		}
		printf("recv:%s\n",msg.data);
		if(0 == strcmp("quit",msg.data)) break;


		msg.type = 6;
		printf(">>>");
		scanf("%s",msg.data);
		//send message
		if(msgsnd(msgid,&msg,strlen(msg.data)+1,0))
		{
			perror("msgsnd");
			break;
		}
		if(0 == strcmp("quit",msg.data)) break;
	}
	
	printf("End of communication!\n");
	return 0;
}

Amount of information:

Basic features: a "global variable" maintained by kernel sharing, which is used to record the number of shared resources and limit the process's access to resources

1. If the value of the variable is greater than 0, the resource can be used. At this time, the variable value needs to be - 1 before the resource can be used

2. If the value of the variable is equal to 0, it indicates that the available resources can be used. At this time, the process will enter sleep until the variable is greater than 0, and the process will be awakened. Execute step 1

3. When the resource is used up, the value of the variable is + 1, and the dormant process can be awakened

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
Function: create or obtain information volume
key: IPC Key value
nsems: The number of semaphores is generally written as 1
semflg: 
	IPC_CREAT	Create semaphore
	IPC_EXCL	Return if present-1
	mode: 		jurisdiction
 Return value: IPC identifier 	Failure Return-1

int semop(int semid, struct sembuf *sops, unsigned nsops);
Function: add and subtract semaphores
semid: IPC identifier 
sops: 
		struct sembuf
		{
           unsigned short sem_num;  //	Semaphore subscript
           short  sem_op;   		
           			1		Semaphore+1
           			0		The value of the waiting semaphore is 0
           		   >0		Semaphore-1,If not-1,Then blocking
           short  sem_flg; 
           			IPC_NOWAIT	No blocking
           			SEM_UNDO	If the semaphore is not restored after the process is terminated, the system will restore it automatically
		}
nsops: express sops How many structures does the pointer point to? Usually write 1

int semctl(int semid, int semnum, int cmd, ...);
Function: delete/Control semaphore
semid: IPC identifier 
semnum: Semaphore subscript
cmd: 
	IPC_STAT	Get shared memory properties	
	IPC_SET		Set shared memory properties	
	IPC_RMID	Delete shared memory		 
	GETALL		Get the values of all semaphores
    GETVAL		Gets the value of a semaphore
    GETNCNT		Gets the number of all processes waiting for subtraction
    SETALL		Set the values of all semaphores
    SETVAL		Set the value of a semaphore
   union semun {
           int              val;    //	Used to set the value of the semaphore
           struct semid_ds *buf;    //	Properties of semaphores
           unsigned short  *array;  //	Get / set the value of semaphore in batch  
   };

Donkey riding

#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>

int main(int argc,const char* argv[])
{
	//	Create semaphore
	int semid = semget(ftok(".",119),1,IPC_CREAT|0644);
	if(0 > semid)
	{
		perror("semget");
		return -1;
	}

	//	Sets the value of the semaphore
	if(semctl(semid,0,SETVAL,5))
	{
		perror("semctl");
		return -1;
	}
//	printf("%d\n",semctl(semid,0,GETVAL));
	printf("I am the process%u,I have%d A little donkey\n",getpid(),semctl(semid,0,GETVAL));


	//	Ten processes compete for five resources
	for(int i=0; i<10; i++)
	{
		pid_t pid = fork();
		if(0 == pid)
		{
			struct sembuf buf = {0,-1,0};
			semop(semid,&buf,1);
			printf("I am a subprocess%u,I rode a little donkey,also%d A little donkey\n",getpid(),semctl(semid,0,GETVAL));
			sleep(i);
			buf.sem_op = 1;
			semop(semid,&buf,1);
			printf("I am a subprocess%u,I also bought a little donkey,also%d A little donkey\n",getpid(),semctl(semid,0,GETVAL));
			return 0;
		}
	}

	while(-1 !=wait(NULL));

	printf("I am the process%u,I have%d A little donkey\n",getpid(),semctl(semid,0,GETVAL));
	if(semctl(semid,0,IPC_RMID))
	{
		perror("semctl");
		return -1;
	}
}

Added by menios on Mon, 31 Jan 2022 23:34:31 +0200