semget,semop and semctl functions

本文详细介绍了在操作系统中使用信号量进行进程同步的方法,包括semget、semop和semctl三个核心函数的用法及参数说明。解释了如何创建、操作和控制信号量集,以及信号量在实现互斥和同步中的作用。

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } -->

SEMGET FUNCTION

The prototype of semget is

int semget(key_t key , int nsems , int semflg );

We use semget() to get a semaphore set ID. After we call semget() successfully, it returns a non-negative integer, often called sem_id, which other semaphore functions use to access the semaphore set. On error, it returns -1.

Note that the phrase is "semaphore set". That means it is an array of semaphores, and the 2nd argument nsems decides how many elements the array owns, though almost we just need 1.

I was a little confused by the 1st argument key at first, because I don't know how it works.

Then I looked up the linux manual page.

Here comes the partial description of semget():

The semget() system call returns the semaphore set identifier associated with the argument key. A new set of nsems semaphores is created if key has the value IPC_PRIVATE or if no existing semaphore set is associated with key and IPC_CREAT is specified in semflg.

And then I know the parameter key is an integer associated to the special semaphore. When the system plans to create a new semaphore, it checks the key first to see if another one connected to the key has existed, if so, the system fails with errno.

On another occasion, if we set the key to IPC_PRIVATE, then we can obtain a private semaphore, that means the semaphore can only be accessed by one particular process or thread, so we know it is useless. Always we should provide a unique and non-zero integer for key.



SEMOP FUNCTION

The prototype of semop is

int semop(int semid , struct sembuf * sops , unsigned nsops );

We could easily know that this function is used to perform some operation on semaphores from the name of it.

But how it actually works?

As is refered to above, the function semget() returns an ID pointing to an array of semaphores, and the argument nsems in semget() indicates how many they are. So when we decide to make some change on semaphores, we should know where the semaphores are first, so we get the semid pointing to the array. And then we should know how many operations will be performed, that is why the 3 rd parameter nsops exists.

Finally, how we make changes on the semaphores? We use struct sembuf.

The structure comes below:

unsigned short sem_num; /* semaphore number */

short sem_op; /* semaphore operation */

short sem_flg; /* operation flags */

sem_num indicates which semaphore in the set would be operate, usually it is set to 0.

sem_op holds the value by which the semaphore would change. Generally, +1 is used for P operation and -1 for V to say that the critical section is available now.

It is good to set the sem_flg to SEM_UNDO, so that when the process terminates, the operation could be undone automatically.

On the whole, we use semid to point to the destination set, sops to indicates where the operation array is, then the system performs nsops operation to make changes on the semaphores in the sops array order.

For instance, we call semop(sem_id, buf, 3). The 2nd argument buf is a pointer pointing to an array of struct sembuf owning at least 3 elements. The system catch the 3rd argument 3 to know 3 operations will be performed with the information given by the 2nd argument buf. We said that these operations will be performed in the sops array order, so the system would just make changes on semaphores whose ID is among buf[0].sem_num, buf[1].sem_num and buf[2].sem_num, and of course, each operation will be done according to the buf[i].sem_op, in which i is among 0, 1, 2.

Note that the operation is done atomically and automatically.



SEMCTL FUNCTION

The prototype of the semctl is:

int semctl(int semid , int semnum , int cmd , ...);

This function performs an direct operation on the semnum-th semaphore in the semaphore set whose ID is semid with the argument cmd.

There are many kinds of cmd, which affects the 4th argument's existence.Usually we use two command, SETVAL and IPC_RMID.

For command SETVAL we need a 4th argument to indicate the value to set to the semnum-th semaphore in the set owning the ID semid.

The 4th argument structure follows:

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO

(Linux-specific) */

};

And for command IPC_RMID, we aims at removing the semaphore set whose ID is semid, and awakening the processes blocked for the set. Under this circumstance, the argument semnum is ignored.


Jason Lee

2009-11-14 p.m

P.S. 一家之言,如有不足,请多加指正。

/** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file A.c * brief process A(Sending process) * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 12Aug25 * */ /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include "shm_comm.h" /**************************************************************************************************/ /* GLOBAL_FUNCTIONS */ /**************************************************************************************************/ void sender_process() { /** * Initialize shared memory segments for data transmission and acknowledgment * Create with read/write permissions for all users (0666) */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), IPC_CREAT | 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), IPC_CREAT | 0666); /** Attach shared memory segments to process address space */ ShmDataSegment *shm_data = (ShmDataSegment*)shmat(shmid_a2b, NULL, 0); ShmAckSegment *shm_ack = (ShmAckSegment*)shmat(shmid_b2a, NULL, 0); /** * Create and initialize semaphores for synchronization * A2B channel: * - sem_a2b_empty: Indicates if data buffer is empty (initial value 1) * - sem_a2b_full: Indicates if data buffer is full (initial value 0) * B2A channel: * - sem_b2a_empty: Indicates if ack buffer is empty (initial value 1) * - sem_b2a_full: Indicates if ack buffer is full (initial value 0) */ int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, IPC_CREAT | 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, IPC_CREAT | 0666); semctl(sem_a2b_empty, 0, SETVAL, 1); semctl(sem_a2b_full, 0, SETVAL, 0); semctl(sem_b2a_empty, 0, SETVAL, 1); semctl(sem_b2a_full, 0, SETVAL, 0); /** Test data blocks to be transmitted every second */ char *data[] = { "First data block (M bytes)", /** Transmission at second 1 */ "Second data block (N bytes)", /** Transmission at second 2 */ "Third data block (P bytes)", /** Transmission at second 3 */ "Fourth data block (Q bytes)" /** Transmission at second 4 */ }; /** Main transmission loop - sends data every second */ int i = 0; while(1) { /** Wait for one second before sending next data block */ sleep(1); /** Get current time and format it as YYYY-MM-DD HH:MM:SS */ time_t current_time = time(NULL); struct tm *tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); /** Prepare data for transmission */ size_t len = strlen(data[i]) + 1; /** Include null terminator */ /** * Send data through A2B channel: * 1. Wait for buffer to be empty (P operation on empty semaphore) * 2. Copy data to shared memory * 3. Calculate and store checksum * 4. Signal buffer is full (V operation on full semaphore) */ P(sem_a2b_empty); memcpy(shm_data->data, data[i], len); shm_data->size = len; shm_data->crc = calculate_checksum(shm_data->data, len); V(sem_a2b_full); /** Log transmission activity */ printf("[A] %s: 我发送了%zu字节数据给B\n", time_str, len); /** * Wait for acknowledgment from B: * 1. Wait for ack buffer to be full (P operation on full semaphore) * 2. Read acknowledgment status and size * 3. Signal ack buffer is empty (V operation on empty semaphore) */ P(sem_b2a_full); int ack_status = shm_ack->ack_status; size_t ack_size = shm_ack->size; V(sem_b2a_empty); /** Log acknowledgment status based on received response */ if (ack_status == 1) { printf("[A] %s: B告诉我收到了%zu字节数据,校验正确\n", time_str, ack_size); } else { printf("[A] %s: B告诉我收到了%zu字节数据,但校验失败\n", time_str, ack_size); } i = ( i + 1) % 4; } /** * Cleanup resources: * 1. Detach shared memory segments * 2. Mark shared memory segments for deletion * 3. Remove semaphores */ shmdt(shm_data); shmdt(shm_ack); shmctl(shmid_a2b, IPC_RMID, NULL); shmctl(shmid_b2a, IPC_RMID, NULL); semctl(sem_a2b_empty, 0, IPC_RMID, 0); semctl(sem_a2b_full, 0, IPC_RMID, 0); semctl(sem_b2a_empty, 0, IPC_RMID, 0); semctl(sem_b2a_full, 0, IPC_RMID, 0); return; } /** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file shared_memory.h * brief Implementing inter process communication through shared memory * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 12Aug25 * */ #ifndef SHM_COMM_H #define SHM_COMM_H /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/ipc.h> #include <time.h> #include <unistd.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ /** Define shared memory keys */ #define SHM_A2B_KEY 0x1234 #define SHM_B2A_KEY 0x5678 /** Define semaphore keys */ #define SEM_A2B_EMPTY_KEY 0x1111 #define SEM_A2B_FULL_KEY 0x2222 #define SEM_B2A_EMPTY_KEY 0x3333 #define SEM_B2A_FULL_KEY 0x4444 /** Semaphore operation macros */ #define P(sem_id) semaphore_operation(sem_id, -1, 0) #define V(sem_id) semaphore_operation(sem_id, 1, 0) /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /** Define shared memory segment structure for data transmission */ typedef struct ShmDataSegment { char data[1024]; /** Buffer for data storage */ size_t size; /** Actual size of transmitted data */ unsigned long crc; /** CRC checksum for data validation */ } ShmDataSegment; /** Define shared memory segment structure for acknowledgment */ typedef struct ShmAckSegment { int ack_status; /** 1 = success, 2 = checksum failure */ size_t size; /** Size of the acknowledged data */ } ShmAckSegment; /**************************************************************************************************/ /* FUNCTIONS */ /**************************************************************************************************/ static inline unsigned short calculate_checksum(const char *data, int len) { unsigned short sum = 0; int i; for (i = 0; i < len; i++) { sum += (unsigned char)data[i]; } return sum; } /** Semaphore operation function */ static inline void semaphore_operation(int sem_id, int op, int flg) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = op; sops.sem_flg = flg; semop(sem_id, &sops, 1); } #endif /** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file main.c * brief Master process for shared memory communication * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 15Aug25 */ #include "shm_comm.h" #include <sys/wait.h> #include <unistd.h> extern void sender_process(); extern void receiver_process(); int main() { /* Create shared memory segments for data transmission and acknowledgment */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), IPC_CREAT | 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), IPC_CREAT | 0666); /* Initialize semaphores for synchronization */ int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, IPC_CREAT | 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, IPC_CREAT | 0666); semctl(sem_a2b_empty, 0, SETVAL, 1); semctl(sem_a2b_full, 0, SETVAL, 0); semctl(sem_b2a_empty, 0, SETVAL, 1); semctl(sem_b2a_full, 0, SETVAL, 0); /* Create sender process */ pid_t sender_pid = fork(); if (sender_pid == 0) { sender_process(); exit(0); } /* Create receiver process */ pid_t receiver_pid = fork(); if (receiver_pid == 0) { receiver_process(); exit(0); } /* Wait for child processes to complete */ waitpid(sender_pid, NULL, 0); waitpid(receiver_pid, NULL, 0); /* Cleanup IPC resources */ shmctl(shmid_a2b, IPC_RMID, NULL); shmctl(shmid_b2a, IPC_RMID, NULL); semctl(sem_a2b_empty, 0, IPC_RMID, 0); semctl(sem_a2b_full, 0, IPC_RMID, 0); semctl(sem_b2a_empty, 0, IPC_RMID, 0); semctl(sem_b2a_full, 0, IPC_RMID, 0); return 0; }/** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file B.c * brief process B(Receiving process) * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 13Aug25 * */ /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include "shm_comm.h" /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /** Statistics tracking structure */ typedef struct { int recv_count; /** Total receptions */ int success_count; /** Valid checksums */ int fail_count; /** Checksum mismatches */ size_t total_bytes; /** Cumulative bytes received */ } Stats; /**************************************************************************************************/ /* GLOBAL_FUNCTIONS */ /**************************************************************************************************/ void receiver_process() { /** * Attach to existing shared memory segments * Note: No IPC_CREAT flag since segments should already exist */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), 0666); ShmDataSegment *shm_data = (ShmDataSegment*)shmat(shmid_a2b, NULL, 0); ShmAckSegment *shm_ack = (ShmAckSegment*)shmat(shmid_b2a, NULL, 0); /** Get existing semaphores */ int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, 0666); /** Main reception loop - continuously checks for incoming data */ while (1) { /** * Wait for data to arrive in A2B channel: * P operation on full semaphore (blocks until data is available) */ P(sem_a2b_full); /** Get current time for logging */ time_t current_time = time(NULL); struct tm *tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); /** Check for termination condition (size=0) */ // size_t size = sizeof(*shm_data); // { // V(sem_a2b_empty); /** Release buffer before breaking */ // break; // } size_t size = shm_data->size; /** * Validate received data: * 1. Calculate checksum of received data * 2. Compare with transmitted checksum */ unsigned short calc_crc = calculate_checksum(shm_data->data, size); int crc_ok = (calc_crc == shm_data->crc) ? 1 : 0; /** Log reception status based on checksum validation */ if (crc_ok) { printf("[B] %s: 我从A接收了%zu字节数据,校验正确,通知A接收了%zu字节数据,校验正确。\n", time_str, size, size); } else { printf("[B] %s: 我从A接收了%zu字节数据,校验错误,通知A接收了%zu字节数据,校验错误。\n", time_str, size, size); } /** * Send acknowledgment through B2A channel: * 1. Wait for ack buffer to be empty (P operation on empty semaphore) * 2. Write acknowledgment status and size * 3. Signal ack buffer is full (V operation on full semaphore) * 4. Release data buffer (V operation on empty semaphore) */ P(sem_b2a_empty); shm_ack->ack_status = crc_ok ? 1 : 2; /** 1=success, 2=checksum failure */ shm_ack->size = size; V(sem_b2a_full); V(sem_a2b_empty); /** Release data buffer for next transmission */ } /** Detach shared memory segments before exit */ shmdt(shm_data); shmdt(shm_ack); return; } 给以上代码写一份设计报告
08-20
ubantu下的项目shared_memory(可正常执行)/** copyright Copyright © 2025 Chendu TP-Link Technologies Co.Ltd. file A.c brief process A(Sending process) author Wang zhiheng wangzhiheng@tp-link.com.hk version 1.0.0 date 12Aug25 */ // /* INCLUDE FILES */ // #include “shm_comm.h” // /* GLOBAL_FUNCTIONS */ // int main() { /** Initialize shared memory segments for data transmission and acknowledgment Create with read/write permissions for all users (0666) */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), IPC_CREAT | 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), IPC_CREAT | 0666); /** Attach shared memory segments to process address space / ShmDataSegment shm_data = (ShmDataSegment)shmat(shmid_a2b, NULL, 0); ShmAckSegment shm_ack = (ShmAckSegment)shmat(shmid_b2a, NULL, 0); /* * Create and initialize semaphores for synchronization * A2B channel: * - sem_a2b_empty: Indicates if data buffer is empty (initial value 1) * - sem_a2b_full: Indicates if data buffer is full (initial value 0) * B2A channel: * - sem_b2a_empty: Indicates if ack buffer is empty (initial value 1) * - sem_b2a_full: Indicates if ack buffer is full (initial value 0) / int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, IPC_CREAT | 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, IPC_CREAT | 0666); semctl(sem_a2b_empty, 0, SETVAL, 1); semctl(sem_a2b_full, 0, SETVAL, 0); semctl(sem_b2a_empty, 0, SETVAL, 1); semctl(sem_b2a_full, 0, SETVAL, 0); /* Test data blocks to be transmitted every second / char data[] = { “First data block (M bytes)”, / Transmission at second 1 / “Second data block (N bytes)”, /* Transmission at second 2 / “Third data block (P bytes)”, /* Transmission at second 3 / “Fourth data block (Q bytes)” /* Transmission at second 4 / }; /* Main transmission loop - sends data every second / int i = 0; while(1) { /* Wait for one second before sending next data block / sleep(1); /* Get current time and format it as YYYY-MM-DD HH:MM:SS / time_t current_time = time(NULL); struct tm tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), “%Y-%m-%d %H:%M:%S”, tm_info); / Prepare data for transmission / size_t len = strlen(data[i]) + 1; /* Include null terminator / /* * Send data through A2B channel: * 1. Wait for buffer to be empty (P operation on empty semaphore) * 2. Copy data to shared memory * 3. Calculate and store checksum * 4. Signal buffer is full (V operation on full semaphore) / P(sem_a2b_empty); memcpy(shm_data->data, data[i], len); shm_data->size = len; shm_data->crc = calculate_checksum(shm_data->data, len); V(sem_a2b_full); /* Log transmission activity / printf(“[A] %s: 我发送了%zu字节数据给B\n”, time_str, len); /* * Wait for acknowledgment from B: * 1. Wait for ack buffer to be full (P operation on full semaphore) * 2. Read acknowledgment status and size * 3. Signal ack buffer is empty (V operation on empty semaphore) / P(sem_b2a_full); int ack_status = shm_ack->ack_status; size_t ack_size = shm_ack->size; V(sem_b2a_empty); /* Log acknowledgment status based on received response / if (ack_status == 1) { printf(“[A] %s: B告诉我收到了%zu字节数据,校验正确\n”, time_str, ack_size); } else { printf(“[A] %s: B告诉我收到了%zu字节数据,但校验失败\n”, time_str, ack_size); } i = ( i + 1) % 4; } /* * Cleanup resources: * 1. Detach shared memory segments * 2. Mark shared memory segments for deletion * 3. Remove semaphores / shmdt(shm_data); shmdt(shm_ack); shmctl(shmid_a2b, IPC_RMID, NULL); shmctl(shmid_b2a, IPC_RMID, NULL); semctl(sem_a2b_empty, 0, IPC_RMID, 0); semctl(sem_a2b_full, 0, IPC_RMID, 0); semctl(sem_b2a_empty, 0, IPC_RMID, 0); semctl(sem_b2a_full, 0, IPC_RMID, 0); return 0; } /* copyright Copyright © 2025 Chendu TP-Link Technologies Co.Ltd. file B.c brief process B(Receiving process) author Wang zhiheng wangzhiheng@tp-link.com.hk version 1.0.0 date 13Aug25 */ // /* INCLUDE FILES */ // #include “shm_comm.h” // /* TYPES */ // /** Statistics tracking structure / typedef struct { int recv_count; /* Total receptions / int success_count; /* Valid checksums / int fail_count; /* Checksum mismatches / size_t total_bytes; /* Cumulative bytes received */ } Stats; // /* GLOBAL_FUNCTIONS */ // int main() { /** Attach to existing shared memory segments Note: No IPC_CREAT flag since segments should already exist */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), 0666); ShmDataSegment shm_data = (ShmDataSegment)shmat(shmid_a2b, NULL, 0); ShmAckSegment shm_ack = (ShmAckSegment)shmat(shmid_b2a, NULL, 0); /** Get existing semaphores / int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, 0666); /* Main reception loop - continuously checks for incoming data / while (1) { /* * Wait for data to arrive in A2B channel: * P operation on full semaphore (blocks until data is available) / P(sem_a2b_full); /* Get current time for logging / time_t current_time = time(NULL); struct tm tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), “%Y-%m-%d %H:%M:%S”, tm_info); / Check for termination condition (size=0) / size_t size = shm_data; { V(sem_a2b_empty); /* Release buffer before breaking / break; } /* * Validate received data: * 1. Calculate checksum of received data * 2. Compare with transmitted checksum / unsigned short calc_crc = calculate_checksum(shm_data->data, size); int crc_ok = (calc_crc == shm_data->crc) ? 1 : 0; /* Log reception status based on checksum validation / if (crc_ok) { printf(“[B] %s: 我从A接收了%zu字节数据,校验正确,通知A接收了%zu字节数据,校验正确。\n”, time_str, size, size); } else { printf(“[B] %s: 我从A接收了%zu字节数据,校验错误,通知A接收了%zu字节数据,校验错误。\n”, time_str, size, size); } /* * Send acknowledgment through B2A channel: * 1. Wait for ack buffer to be empty (P operation on empty semaphore) * 2. Write acknowledgment status and size * 3. Signal ack buffer is full (V operation on full semaphore) * 4. Release data buffer (V operation on empty semaphore) / P(sem_b2a_empty); shm_ack->ack_status = crc_ok ? 1 : 2; /* 1=success, 2=checksum failure / shm_ack->size = size; V(sem_b2a_full); V(sem_a2b_empty); /* Release data buffer for next transmission / } /* Detach shared memory segments before exit */ shmdt(shm_data); shmdt(shm_ack); return 0; } /**# 编译器设置 CC = gcc CFLAGS = -Wall 目标程序 all: sender receiver 编译发送端 sender: A.c shm_comm.h ( C C ) (CC)(CFLAGS) A.c -o sender 编译接收端 receiver: B.c shm_comm.h ( C C ) (CC)(CFLAGS) B.c -o receiver 清理生成的文件 clean: rm -f sender receiver copyright Copyright © 2025 Chendu TP-Link Technologies Co.Ltd. file shared_memory.h brief Implementing inter process communication through shared memory author Wang zhiheng wangzhiheng@tp-link.com.hk version 1.0.0 date 12Aug25 */ #ifndef SHM_COMM_H #define SHM_COMM_H // /* INCLUDE FILES */ // #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/ipc.h> #include <time.h> #include <unistd.h> // /* DEFINES */ // /** Define shared memory keys */ #define SHM_A2B_KEY 0x1234 #define SHM_B2A_KEY 0x5678 /** Define semaphore keys */ #define SEM_A2B_EMPTY_KEY 0x1111 #define SEM_A2B_FULL_KEY 0x2222 #define SEM_B2A_EMPTY_KEY 0x3333 #define SEM_B2A_FULL_KEY 0x4444 /** Semaphore operation macros */ #define P(sem_id) semaphore_operation(sem_id, -1, 0) #define V(sem_id) semaphore_operation(sem_id, 1, 0) // /* TYPES */ // /** Define shared memory segment structure for data transmission / typedef struct ShmDataSegment { char data[1024]; /* Buffer for data storage / size_t size; /* Actual size of transmitted data / unsigned long crc; /* CRC checksum for data validation */ } ShmDataSegment; /** Define shared memory segment structure for acknowledgment / typedef struct ShmAckSegment { int ack_status; /* 1 = success, 2 = checksum failure / size_t size; /* Size of the acknowledged data */ } ShmAckSegment; // /* FUNCTIONS */ // static inline unsigned short calculate_checksum(const char *data, int len) { unsigned short sum = 0; for (int i = 0; i < len; i++) { sum += (unsigned char)data[i]; } return sum; } /** Semaphore operation function */ void semaphore_operation(int sem_id, int op, int flg) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = op; sops.sem_flg = flg; semop(sem_id, &sops, 1); } #endif这是我们的项目,写一下它在openwrt环境下运行的文件树结构和makefile
08-19
详细解读以下代码:/** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file shared_memory.h * brief Implementing inter process communication through shared memory * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 12Aug25 * */ #ifndef SHM_COMM_H #define SHM_COMM_H /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/ipc.h> #include <time.h> #include <unistd.h> /**************************************************************************************************/ /* DEFINES */ /**************************************************************************************************/ /** Define shared memory keys */ #define SHM_A2B_KEY 0x1234 #define SHM_B2A_KEY 0x5678 /** Define semaphore keys */ #define SEM_A2B_EMPTY_KEY 0x1111 #define SEM_A2B_FULL_KEY 0x2222 #define SEM_B2A_EMPTY_KEY 0x3333 #define SEM_B2A_FULL_KEY 0x4444 /** Semaphore operation macros */ #define P(sem_id) semaphore_operation(sem_id, -1, 0) #define V(sem_id) semaphore_operation(sem_id, 1, 0) /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /** Define shared memory segment structure for data transmission */ typedef struct ShmDataSegment { char data[1024]; /** Buffer for data storage */ size_t size; /** Actual size of transmitted data */ unsigned long crc; /** CRC checksum for data validation */ } ShmDataSegment; /** Define shared memory segment structure for acknowledgment */ typedef struct ShmAckSegment { int ack_status; /** 1 = success, 2 = checksum failure */ size_t size; /** Size of the acknowledged data */ } ShmAckSegment; /**************************************************************************************************/ /* FUNCTIONS */ /**************************************************************************************************/ static inline unsigned short calculate_checksum(const char *data, int len) { unsigned short sum = 0; for (int i = 0; i < len; i++) { sum += (unsigned char)data[i]; } return sum; } /** Semaphore operation function */ void semaphore_operation(int sem_id, int op, int flg) { struct sembuf sops; sops.sem_num = 0; sops.sem_op = op; sops.sem_flg = flg; semop(sem_id, &sops, 1); } #endif /** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file A.c * brief process A(Sending process) * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 12Aug25 * */ /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include "shm_comm.h" /**************************************************************************************************/ /* GLOBAL_FUNCTIONS */ /**************************************************************************************************/ int main() { /** * Initialize shared memory segments for data transmission and acknowledgment * Create with read/write permissions for all users (0666) */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), IPC_CREAT | 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), IPC_CREAT | 0666); /** Attach shared memory segments to process address space */ ShmDataSegment *shm_data = (ShmDataSegment*)shmat(shmid_a2b, NULL, 0); ShmAckSegment *shm_ack = (ShmAckSegment*)shmat(shmid_b2a, NULL, 0); /** * Create and initialize semaphores for synchronization * A2B channel: * - sem_a2b_empty: Indicates if data buffer is empty (initial value 1) * - sem_a2b_full: Indicates if data buffer is full (initial value 0) * B2A channel: * - sem_b2a_empty: Indicates if ack buffer is empty (initial value 1) * - sem_b2a_full: Indicates if ack buffer is full (initial value 0) */ int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, IPC_CREAT | 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, IPC_CREAT | 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, IPC_CREAT | 0666); semctl(sem_a2b_empty, 0, SETVAL, 1); semctl(sem_a2b_full, 0, SETVAL, 0); semctl(sem_b2a_empty, 0, SETVAL, 1); semctl(sem_b2a_full, 0, SETVAL, 0); /** Test data blocks to be transmitted every second */ char *data[] = { "First data block (M bytes)", /** Transmission at second 1 */ "Second data block (N bytes)", /** Transmission at second 2 */ "Third data block (P bytes)", /** Transmission at second 3 */ "Fourth data block (Q bytes)" /** Transmission at second 4 */ }; /** Main transmission loop - sends data every second */ int i = 0; while(1) { /** Wait for one second before sending next data block */ sleep(1); /** Get current time and format it as YYYY-MM-DD HH:MM:SS */ time_t current_time = time(NULL); struct tm *tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); /** Prepare data for transmission */ size_t len = strlen(data[i]) + 1; /** Include null terminator */ /** * Send data through A2B channel: * 1. Wait for buffer to be empty (P operation on empty semaphore) * 2. Copy data to shared memory * 3. Calculate and store checksum * 4. Signal buffer is full (V operation on full semaphore) */ P(sem_a2b_empty); memcpy(shm_data->data, data[i], len); shm_data->size = len; shm_data->crc = calculate_checksum(shm_data->data, len); V(sem_a2b_full); /** Log transmission activity */ printf("[A] %s: 我发送了%zu字节数据给B\n", time_str, len); /** * Wait for acknowledgment from B: * 1. Wait for ack buffer to be full (P operation on full semaphore) * 2. Read acknowledgment status and size * 3. Signal ack buffer is empty (V operation on empty semaphore) */ P(sem_b2a_full); int ack_status = shm_ack->ack_status; size_t ack_size = shm_ack->size; V(sem_b2a_empty); /** Log acknowledgment status based on received response */ if (ack_status == 1) { printf("[A] %s: B告诉我收到了%zu字节数据,校验正确\n", time_str, ack_size); } else { printf("[A] %s: B告诉我收到了%zu字节数据,但校验失败\n", time_str, ack_size); } i = ( i + 1) % 4; } /** * Cleanup resources: * 1. Detach shared memory segments * 2. Mark shared memory segments for deletion * 3. Remove semaphores */ shmdt(shm_data); shmdt(shm_ack); shmctl(shmid_a2b, IPC_RMID, NULL); shmctl(shmid_b2a, IPC_RMID, NULL); semctl(sem_a2b_empty, 0, IPC_RMID, 0); semctl(sem_a2b_full, 0, IPC_RMID, 0); semctl(sem_b2a_empty, 0, IPC_RMID, 0); semctl(sem_b2a_full, 0, IPC_RMID, 0); return 0; } /** * copyright Copyright (c) 2025 Chendu TP-Link Technologies Co.Ltd. * * file B.c * brief process B(Receiving process) * * author Wang zhiheng <wangzhiheng@tp-link.com.hk> * version 1.0.0 * date 13Aug25 * */ /**************************************************************************************************/ /* INCLUDE FILES */ /**************************************************************************************************/ #include "shm_comm.h" /**************************************************************************************************/ /* TYPES */ /**************************************************************************************************/ /** Statistics tracking structure */ typedef struct { int recv_count; /** Total receptions */ int success_count; /** Valid checksums */ int fail_count; /** Checksum mismatches */ size_t total_bytes; /** Cumulative bytes received */ } Stats; /**************************************************************************************************/ /* GLOBAL_FUNCTIONS */ /**************************************************************************************************/ int main() { /** * Attach to existing shared memory segments * Note: No IPC_CREAT flag since segments should already exist */ int shmid_a2b = shmget(SHM_A2B_KEY, sizeof(ShmDataSegment), 0666); int shmid_b2a = shmget(SHM_B2A_KEY, sizeof(ShmAckSegment), 0666); ShmDataSegment *shm_data = (ShmDataSegment*)shmat(shmid_a2b, NULL, 0); ShmAckSegment *shm_ack = (ShmAckSegment*)shmat(shmid_b2a, NULL, 0); /** Get existing semaphores */ int sem_a2b_empty = semget(SEM_A2B_EMPTY_KEY, 1, 0666); int sem_a2b_full = semget(SEM_A2B_FULL_KEY, 1, 0666); int sem_b2a_empty = semget(SEM_B2A_EMPTY_KEY, 1, 0666); int sem_b2a_full = semget(SEM_B2A_FULL_KEY, 1, 0666); /** Main reception loop - continuously checks for incoming data */ while (1) { /** * Wait for data to arrive in A2B channel: * P operation on full semaphore (blocks until data is available) */ P(sem_a2b_full); /** Get current time for logging */ time_t current_time = time(NULL); struct tm *tm_info = localtime(&current_time); char time_str[20]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); /** Check for termination condition (size=0) */ size_t size = shm_data->size; if (size == 0) { V(sem_a2b_empty); /** Release buffer before breaking */ break; } /** * Validate received data: * 1. Calculate checksum of received data * 2. Compare with transmitted checksum */ unsigned short calc_crc = calculate_checksum(shm_data->data, size); int crc_ok = (calc_crc == shm_data->crc) ? 1 : 0; /** Log reception status based on checksum validation */ if (crc_ok) { printf("[B] %s: 我从A接收了%zu字节数据,校验正确,通知A接收了%zu字节数据,校验正确。\n", time_str, size, size); } else { printf("[B] %s: 我从A接收了%zu字节数据,校验错误,通知A接收了%zu字节数据,校验错误。\n", time_str, size, size); } /** * Send acknowledgment through B2A channel: * 1. Wait for ack buffer to be empty (P operation on empty semaphore) * 2. Write acknowledgment status and size * 3. Signal ack buffer is full (V operation on full semaphore) * 4. Release data buffer (V operation on empty semaphore) */ P(sem_b2a_empty); shm_ack->ack_status = crc_ok ? 1 : 2; /** 1=success, 2=checksum failure */ shm_ack->size = size; V(sem_b2a_full); V(sem_a2b_empty); /** Release data buffer for next transmission */ } /** Detach shared memory segments before exit */ shmdt(shm_data); shmdt(shm_ack); return 0; }
08-14
乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值