semtimedop系统调用及示例

semtimedop 函数详解

1. 函数介绍

semtimedop 是Linux系统调用,用于对System V信号量集执行原子操作,并支持超时控制。它是 semop 函数的增强版本,允许指定操作的超时时间,避免无限期阻塞。信号量是进程间同步的重要机制,常用于控制对共享资源的访问。

2. 函数原型

#include <sys/sem.h>
#include <sys/types.h>

int semtimedop(int semid, struct sembuf *sops, size_t nsops,
               const struct timespec *timeout);

3. 功能

semtimedop 对指定的信号量集执行一系列原子操作,如果操作不能立即完成且设置了阻塞标志,则在指定的超时时间内等待。该函数提供了精确的时间控制,使得程序可以在等待信号量时避免永久阻塞。

4. 参数

  • int semid: 信号量集标识符(由semget返回)
  • *struct sembuf sops: 信号量操作数组
  • size_t nsops: 操作数组中元素的个数
  • *const struct timespec timeout: 超时时间(NULL表示无限等待)

5. 返回值

  • 成功: 返回0
  • 超时: 返回-1,并设置errno为EAGAIN
  • 失败: 返回-1,并设置相应的errno

6. 相似函数,或关联函数

  • semop: 不带超时的信号量操作函数
  • semget: 获取信号量集
  • semctl: 信号量控制操作
  • semctl: 信号量控制函数

7. 示例代码

示例1:基础semtimedop使用

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

/**
 * 信号量操作结构
 */
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

/**
 * 初始化信号量
 */
int init_semaphore(key_t key, int nsems, int init_val) {
    int semid;
    union semun arg;
    
    // 创建或获取信号量集
    semid = semget(key, nsems, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("semget 失败");
        return -1;
    }
    
    // 初始化信号量值
    arg.val = init_val;
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("semctl 初始化失败");
        return -1;
    }
    
    return semid;
}

/**
 * 演示基础semtimedop使用方法
 */
int demo_semtimedop_basic() {
    int semid;
    struct sembuf sop;
    struct timespec timeout;
    key_t key = ftok(".", 's');
    
    printf("=== 基础semtimedop使用示例 ===\n");
    
    // 初始化信号量(初始值为1,表示资源可用)
    semid = init_semaphore(key, 1, 1);
    if (semid == -1) {
        return -1;
    }
    
    printf("创建信号量集,ID: %d\n", semid);
    
    // 设置超时时间(5秒)
    timeout.tv_sec = 5;
    timeout.tv_nsec = 0;
    
    // 定义P操作(获取信号量)
    sop.sem_num = 0;      // 操作第0个信号量
    sop.sem_op = -1;      // P操作:减1
    sop.sem_flg = 0;      // 阻塞操作
    
    printf("执行P操作(获取信号量)...\n");
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        if (errno == EAGAIN) {
            printf("操作超时\n");
        } else {
            perror("semtimedop P操作失败");
        }
        goto cleanup;
    }
    
    printf("成功获取信号量\n");
    
    // 模拟使用资源
    printf("使用资源中...(3秒)\n");
    sleep(3);
    
    // 定义V操作(释放信号量)
    sop.sem_op = 1;       // V操作:加1
    
    printf("执行V操作(释放信号量)...\n");
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        perror("semtimedop V操作失败");
        goto cleanup;
    }
    
    printf("成功释放信号量\n");
    
cleanup:
    // 清理信号量集
    if (semctl(semid, 0, IPC_RMID) == -1) {
        perror("清理信号量集失败");
    }
    
    return 0;
}

int main() {
    return demo_semtimedop_basic();
}

示例2:多进程同步演示

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

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

/**
 * 创建二进制信号量(互斥锁)
 */
int create_binary_semaphore(key_t key) {
    int semid;
    union semun arg;
    
    semid = semget(key, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("创建信号量失败");
        return -1;
    }
    
    // 初始化为1(可用状态)
    arg.val = 1;
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("初始化信号量失败");
        semctl(semid, 0, IPC_RMID);
        return -1;
    }
    
    return semid;
}

/**
 * 获取互斥锁
 */
int acquire_mutex(int semid, int timeout_sec) {
    struct sembuf sop;
    struct timespec timeout;
    
    sop.sem_num = 0;
    sop.sem_op = -1;
    sop.sem_flg = 0;
    
    timeout.tv_sec = timeout_sec;
    timeout.tv_nsec = 0;
    
    return semtimedop(semid, &sop, 1, &timeout);
}

/**
 * 释放互斥锁
 */
int release_mutex(int semid) {
    struct sembuf sop;
    
    sop.sem_num = 0;
    sop.sem_op = 1;
    sop.sem_flg = 0;
    
    return semop(semid, &sop, 1);
}

/**
 * 演示多进程同步
 */
int demo_multiprocess_synchronization() {
    int semid;
    key_t key = ftok(".", 'm');
    int shared_resource = 0;
    
    printf("=== 多进程同步演示 ===\n");
    
    // 创建互斥信号量
    semid = create_binary_semaphore(key);
    if (semid == -1) {
        return -1;
    }
    
    printf("创建互斥信号量,ID: %d\n", semid);
    
    // 创建多个子进程
    for (int i = 0; i < 3; i++) {
        if (fork() == 0) {
            // 子进程代码
            pid_t pid = getpid();
            printf("子进程 %d 启动\n", pid);
            
            // 尝试获取互斥锁(超时3秒)
            if (acquire_mutex(semid, 3) == -1) {
                if (errno == EAGAIN) {
                    printf("子进程 %d: 获取锁超时\n", pid);
                } else {
                    printf("子进程 %d: 获取锁失败: %s\n", pid, strerror(errno));
                }
                exit(1);
            }
            
            printf("子进程 %d: 成功获取锁\n", pid);
            
            // 模拟临界区操作
            printf("子进程 %d: 访问共享资源\n", pid);
            sleep(2);  // 模拟处理时间
            
            // 释放互斥锁
            if (release_mutex(semid) == -1) {
                printf("子进程 %d: 释放锁失败: %s\n", pid, strerror(errno));
            } else {
                printf("子进程 %d: 成功释放锁\n", pid);
            }
            
            exit(0);
        }
    }
    
    // 父进程等待所有子进程完成
    for (int i = 0; i < 3; i++) {
        int status;
        wait(&status);
        if (WIFEXITED(status)) {
            printf("子进程 %d 退出,状态码: %d\n", 
                   i + 1, WEXITSTATUS(status));
        }
    }
    
    // 清理信号量
    semctl(semid, 0, IPC_RMID);
    
    return 0;
}

int main() {
    return demo_multiprocess_synchronization();
}

示例3:生产者-消费者模型

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

#define BUFFER_SIZE 5
#define MAX_ITEMS 10

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

// 信号量索引定义
#define EMPTY_SEM 0    // 空槽位计数
#define FULL_SEM 1     // 满槽位计数
#define MUTEX_SEM 2    // 缓冲区互斥锁

/**
 * 初始化生产者-消费者信号量
 */
int init_pc_semaphores(key_t key) {
    int semid;
    union semun arg;
    unsigned short values[3] = {BUFFER_SIZE, 0, 1};  // empty, full, mutex
    
    // 创建包含3个信号量的信号量集
    semid = semget(key, 3, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("创建信号量集失败");
        return -1;
    }
    
    // 初始化信号量值
    arg.array = values;
    if (semctl(semid, 0, SETALL, arg) == -1) {
        perror("初始化信号量失败");
        semctl(semid, 0, IPC_RMID);
        return -1;
    }
    
    return semid;
}

/**
 * 生产者操作
 */
int producer_operation(int semid, int item, int timeout_sec) {
    struct sembuf sops[2];
    struct timespec timeout;
    
    // 设置超时时间
    timeout.tv_sec = timeout_sec;
    timeout.tv_nsec = 0;
    
    // 1. 等待空槽位 (P(empty))
    sops[0].sem_num = EMPTY_SEM;
    sops[0].sem_op = -1;
    sops[0].sem_flg = 0;
    
    // 2. 获取缓冲区互斥锁 (P(mutex))
    sops[1].sem_num = MUTEX_SEM;
    sops[1].sem_op = -1;
    sops[1].sem_flg = 0;
    
    printf("生产者: 尝试生产项目 %d\n", item);
    
    // 执行P操作
    if (semtimedop(semid, sops, 2, &timeout) == -1) {
        if (errno == EAGAIN) {
            printf("生产者: 等待超时,无法生产项目 %d\n", item);
        } else {
            printf("生产者: 操作失败: %s\n", strerror(errno));
        }
        return -1;
    }
    
    // 模拟生产过程
    printf("生产者: 正在生产项目 %d\n", item);
    sleep(1);
    printf("生产者: 生产完成项目 %d\n", item);
    
    // 释放互斥锁和增加满槽位计数
    sops[0].sem_num = MUTEX_SEM;
    sops[0].sem_op = 1;   // V(mutex)
    sops[1].sem_num = FULL_SEM;
    sops[1].sem_op = 1;   // V(full)
    
    if (semop(semid, sops, 2) == -1) {
        perror("生产者: 释放信号量失败");
        return -1;
    }
    
    return 0;
}

/**
 * 消费者操作
 */
int consumer_operation(int semid, int *item, int timeout_sec) {
    struct sembuf sops[2];
    struct timespec timeout;
    
    // 设置超时时间
    timeout.tv_sec = timeout_sec;
    timeout.tv_nsec = 0;
    
    // 1. 等待满槽位 (P(full))
    sops[0].sem_num = FULL_SEM;
    sops[0].sem_op = -1;
    sops[0].sem_flg = 0;
    
    // 2. 获取缓冲区互斥锁 (P(mutex))
    sops[1].sem_num = MUTEX_SEM;
    sops[1].sem_op = -1;
    sops[1].sem_flg = 0;
    
    printf("消费者: 尝试消费项目\n");
    
    // 执行P操作
    if (semtimedop(semid, sops, 2, &timeout) == -1) {
        if (errno == EAGAIN) {
            printf("消费者: 等待超时,无项目可消费\n");
        } else {
            printf("消费者: 操作失败: %s\n", strerror(errno));
        }
        return -1;
    }
    
    // 模拟消费过程
    *item = rand() % 100;  // 模拟消费的项目
    printf("消费者: 正在消费项目 %d\n", *item);
    sleep(1);
    printf("消费者: 消费完成项目 %d\n", *item);
    
    // 释放互斥锁和增加空槽位计数
    sops[0].sem_num = MUTEX_SEM;
    sops[0].sem_op = 1;   // V(mutex)
    sops[1].sem_num = EMPTY_SEM;
    sops[1].sem_op = 1;   // V(empty)
    
    if (semop(semid, sops, 2) == -1) {
        perror("消费者: 释放信号量失败");
        return -1;
    }
    
    return 0;
}

/**
 * 演示生产者-消费者模型
 */
int demo_producer_consumer() {
    int semid;
    key_t key = ftok(".", 'p');
    
    printf("=== 生产者-消费者模型演示 ===\n");
    printf("缓冲区大小: %d\n", BUFFER_SIZE);
    printf("生产/消费项目数: %d\n", MAX_ITEMS);
    
    // 初始化信号量
    semid = init_pc_semaphores(key);
    if (semid == -1) {
        return -1;
    }
    
    printf("创建生产者-消费者信号量集,ID: %d\n", semid);
    
    // 创建生产者进程
    if (fork() == 0) {
        // 生产者进程
        srand(getpid());
        printf("生产者进程启动 (PID: %d)\n", getpid());
        
        for (int i = 1; i <= MAX_ITEMS; i++) {
            if (producer_operation(semid, i, 5) == -1) {
                printf("生产者: 生产项目 %d 失败\n", i);
                break;
            }
            sleep(1);  // 生产间隔
        }
        
        printf("生产者进程结束\n");
        exit(0);
    }
    
    // 创建消费者进程
    if (fork() == 0) {
        // 消费者进程
        srand(getpid() + 1000);
        printf("消费者进程启动 (PID: %d)\n", getpid());
        
        for (int i = 1; i <= MAX_ITEMS; i++) {
            int item;
            if (consumer_operation(semid, &item, 5) == -1) {
                printf("消费者: 消费项目失败\n");
                break;
            }
            sleep(2);  // 消费间隔
        }
        
        printf("消费者进程结束\n");
        exit(0);
    }
    
    // 父进程等待子进程完成
    int status;
    wait(&status);
    wait(&status);
    
    // 显示最终信号量状态
    union semun arg;
    unsigned short values[3];
    arg.array = values;
    
    if (semctl(semid, 0, GETALL, arg) != -1) {
        printf("\n最终信号量状态:\n");
        printf("  空槽位: %d\n", values[EMPTY_SEM]);
        printf("  满槽位: %d\n", values[FULL_SEM]);
        printf("  互斥锁: %d\n", values[MUTEX_SEM]);
    }
    
    // 清理信号量集
    semctl(semid, 0, IPC_RMID);
    
    return 0;
}

int main() {
    return demo_producer_consumer();
}

示例4:超时控制演示

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

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

/**
 * 创建计数信号量
 */
int create_counting_semaphore(key_t key, int initial_value) {
    int semid;
    union semun arg;
    
    semid = semget(key, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("创建计数信号量失败");
        return -1;
    }
    
    arg.val = initial_value;
    if (semctl(semid, 0, SETVAL, arg) == -1) {
        perror("初始化计数信号量失败");
        semctl(semid, 0, IPC_RMID);
        return -1;
    }
    
    return semid;
}

/**
 * 演示不同超时设置
 */
int demo_timeout_settings() {
    int semid;
    struct sembuf sop;
    struct timespec timeout;
    key_t key = ftok(".", 't');
    
    printf("=== 超时控制演示 ===\n");
    
    // 创建计数信号量,初始值为0(无资源可用)
    semid = create_counting_semaphore(key, 0);
    if (semid == -1) {
        return -1;
    }
    
    printf("创建计数信号量(初始值: 0),ID: %d\n", semid);
    
    // 定义P操作
    sop.sem_num = 0;
    sop.sem_op = -1;  // 请求资源
    sop.sem_flg = 0;  // 阻塞操作
    
    printf("\n1. 测试短超时(1秒):\n");
    timeout.tv_sec = 1;
    timeout.tv_nsec = 0;
    
    clock_t start = clock();
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        if (errno == EAGAIN) {
            clock_t end = clock();
            double elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
            printf("  操作超时,等待时间: %.2f 秒\n", elapsed);
        } else {
            printf("  操作失败: %s\n", strerror(errno));
        }
    }
    
    printf("\n2. 测试中等超时(3秒):\n");
    timeout.tv_sec = 3;
    timeout.tv_nsec = 0;
    
    start = clock();
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        if (errno == EAGAIN) {
            clock_t end = clock();
            double elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
            printf("  操作超时,等待时间: %.2f 秒\n", elapsed);
        } else {
            printf("  操作失败: %s\n", strerror(errno));
        }
    }
    
    printf("\n3. 测试精确超时(1.5秒):\n");
    timeout.tv_sec = 1;
    timeout.tv_nsec = 500000000;  // 500毫秒
    
    start = clock();
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        if (errno == EAGAIN) {
            clock_t end = clock();
            double elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
            printf("  操作超时,等待时间: %.2f 秒\n", elapsed);
        } else {
            printf("  操作失败: %s\n", strerror(errno));
        }
    }
    
    printf("\n4. 测试零超时(立即返回):\n");
    timeout.tv_sec = 0;
    timeout.tv_nsec = 0;
    
    if (semtimedop(semid, &sop, 1, &timeout) == -1) {
        if (errno == EAGAIN) {
            printf("  立即返回,操作无法完成\n");
        } else {
            printf("  操作失败: %s\n", strerror(errno));
        }
    }
    
    printf("\n5. 测试NULL超时(无限等待):\n");
    printf("  注意:这会导致无限期等待,需要外部干预\n");
    printf("  演示跳过此测试以避免阻塞\n");
    
    // 启动一个进程来释放信号量
    if (fork() == 0) {
        sleep(2);  // 等待主进程开始等待
        
        // 释放信号量
        sop.sem_op = 1;  // V操作
        if (semop(semid, &sop, 1) == -1) {
            perror("释放信号量失败");
        } else {
            printf("  后台进程:信号量已释放\n");
        }
        exit(0);
    }
    
    // 等待一小段时间后测试
    sleep(1);
    timeout.tv_sec = 5;
    timeout.tv_nsec = 0;
    
    printf("  等待信号量释放(5秒超时)...\n");
    if (semtimedop(semid, &sop, 1, &timeout) == 0) {
        printf("  成功获取信号量\n");
    } else {
        printf("  获取信号量失败: %s\n", strerror(errno));
    }
    
    // 等待后台进程完成
    int status;
    wait(&status);
    
    // 清理
    semctl(semid, 0, IPC_RMID);
    
    return 0;
}

int main() {
    return demo_timeout_settings();
}

示例5:复杂信号量操作

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

union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

/**
 * 创建多个信号量的信号量集
 */
int create_multi_semaphore(key_t key, int nsems) {
    int semid;
    
    semid = semget(key, nsems, IPC_CREAT | 0666);
    if (semid == -1) {
        perror("创建多信号量集失败");
        return -1;
    }
    
    // 初始化所有信号量为1
    unsigned short *values = malloc(nsems * sizeof(unsigned short));
    if (!values) {
        perror("分配内存失败");
        semctl(semid, 0, IPC_RMID);
        return -1;
    }
    
    for (int i = 0; i < nsems; i++) {
        values[i] = 1;
    }
    
    union semun arg;
    arg.array = values;
    if (semctl(semid, 0, SETALL, arg) == -1) {
        perror("初始化多信号量失败");
        free(values);
        semctl(semid, 0, IPC_RMID);
        return -1;
    }
    
    free(values);
    return semid;
}

/**
 * 演示复杂的多信号量操作
 */
int demo_complex_operations() {
    int semid;
    struct sembuf sops[5];
    struct timespec timeout;
    key_t key = ftok(".", 'c');
    int num_semaphores = 5;
    
    printf("=== 复杂信号量操作演示 ===\n");
    printf("创建包含 %d 个信号量的信号量集\n", num_semaphores);
    
    // 创建信号量集
    semid = create_multi_semaphore(key, num_semaphores);
    if (semid == -1) {
        return -1;
    }
    
    printf("信号量集创建成功,ID: %d\n", semid);
    
    // 设置超时时间
    timeout.tv_sec = 10;
    timeout.tv_nsec = 0;
    
    // 演示原子性操作:同时操作多个信号量
    printf("\n1. 原子性多信号量操作:\n");
    printf("   同时获取信号量 0, 1, 2\n");
    
    // 同时获取3个信号量(P操作)
    for (int i = 0; i < 3; i++) {
        sops[i].sem_num = i;
        sops[i].sem_op = -1;
        sops[i].sem_flg = 0;
    }
    
    if (semtimedop(semid, sops, 3, &timeout) == 0) {
        printf("   成功原子性获取3个信号量\n");
        
        // 模拟使用资源
        printf("   使用获取的资源...\n");
        sleep(2);
        
        // 同时释放3个信号量(V操作)
        for (int i = 0; i < 3; i++) {
            sops[i].sem_op = 1;
        }
        
        if (semop(semid, sops, 3) == 0) {
            printf("   成功原子性释放3个信号量\n");
        } else {
            perror("   释放信号量失败");
        }
    } else {
        printf("   获取信号量失败: %s\n", strerror(errno));
    }
    
    // 演示混合操作:获取和释放不同信号量
    printf("\n2. 混合信号量操作:\n");
    printf("   获取信号量0,释放信号量1\n");
    
    sops[0].sem_num = 0;
    sops[0].sem_op = -1;  // 获取
    sops[0].sem_flg = 0;
    
    sops[1].sem_num = 1;
    sops[1].sem_op = 1;   // 释放
    sops[1].sem_flg = 0;
    
    if (semtimedop(semid, sops, 2, &timeout) == 0) {
        printf("   混合操作成功\n");
    } else {
        printf("   混合操作失败: %s\n", strerror(errno));
    }
    
    // 演示条件操作:使用SEM_UNDO标志
    printf("\n3. 带自动回滚的操作:\n");
    printf("   使用SEM_UNDO标志,进程退出时自动释放\n");
    
    sops[0].sem_num = 2;
    sops[0].sem_op = -1;
    sops[0].sem_flg = SEM_UNDO;  // 自动回滚
    
    if (semtimedop(semid, sops, 1, &timeout) == 0) {
        printf("   获取信号量2(带自动回滚)\n");
        printf("   程序退出时会自动释放该信号量\n");
        
        // 模拟程序继续运行
        printf("   程序继续运行中...\n");
        sleep(1);
        
        // 不显式释放,依赖SEM_UNDO
    } else {
        printf("   获取信号量失败: %s\n", strerror(errno));
    }
    
    // 演示NOWAIT操作
    printf("\n4. 非阻塞操作:\n");
    printf("   使用IPC_NOWAIT标志\n");
    
    sops[0].sem_num = 3;
    sops[0].sem_op = -1;
    sops[0].sem_flg = IPC_NOWAIT;  // 非阻塞
    
    if (semtimedop(semid, sops, 1, NULL) == 0) {
        printf("   非阻塞获取信号量3成功\n");
        // 立即释放
        sops[0].sem_op = 1;
        sops[0].sem_flg = 0;
        semop(semid, sops, 1);
    } else {
        if (errno == EAGAIN) {
            printf("   信号量3不可用,立即返回\n");
        } else {
            printf("   操作失败: %s\n", strerror(errno));
        }
    }
    
    // 显示当前信号量状态
    printf("\n5. 当前信号量状态:\n");
    unsigned short *values = malloc(num_semaphores * sizeof(unsigned short));
    if (values) {
        union semun arg;
        arg.array = values;
        
        if (semctl(semid, 0, GETALL, arg) != -1) {
            for (int i = 0; i < num_semaphores; i++) {
                printf("   信号量 %d: %d\n", i, values[i]);
            }
        }
        free(values);
    }
    
    // 清理
    semctl(semid, 0, IPC_RMID);
    
    return 0;
}

int main() {
    return demo_complex_operations();
}

semtimedop 使用注意事项

系统要求:

  1. 内核版本: 需要Linux 2.6.12或更高版本
  2. 架构支持: 支持所有主流架构
  3. 编译环境: 需要正确的头文件包含

参数验证:

  1. 信号量ID有效性: 确保semid有效且未被删除
  2. 操作数组合法性: 确保sops指针有效且nsops合理
  3. 超时参数: timeout可以为NULL(无限等待)或有效时间结构

错误处理:

  1. EAGAIN: 操作超时
  2. EINTR: 被信号中断
  3. EINVAL: 参数无效
  4. EACCES: 权限不足
  5. EIDRM: 信号量集已被删除
  6. ENOMEM: 内存不足

性能考虑:

1. 超时设置: 合理设置超时时间避免过度等待
2. 原子性: 多信号量操作保证原子性
3. 资源清理: 及时清理不再使用的信号量

最佳实践:

1. 超时控制: 始终考虑设置合理的超时时间
2. 错误恢复: 妥善处理超时和错误情况
3. 资源管理: 及时清理信号量资源
4. 并发安全: 确保多进程/线程环境下的正确性

信号量操作结构详解

struct sembuf 结构:

struct sembuf {
    unsigned short sem_num;  // 信号量编号
    short sem_op;           // 操作类型
    short sem_flg;          // 操作标志
};

操作类型 (sem_op):

  • 正值: V操作(释放资源),将值加到信号量上
  • 负值: P操作(获取资源),从信号量中减去该值
  • 零值: 等待信号量变为0

操作标志 (sem_flg):

  • SEM_UNDO: 操作完成后自动撤销(进程退出时)
  • IPC_NOWAIT: 非阻塞操作,如果不能立即完成则返回错误
  • 0: 默认阻塞操作

常见使用场景

1. 互斥锁:

// 获取锁
sop.sem_op = -1;
semtimedop(semid, &sop, 1, &timeout);

// 释放锁
sop.sem_op = 1;
semop(semid, &sop, 1);

2. 资源计数:

// 请求资源
sop.sem_op = -1;
semtimedop(semid, &sop, 1, &timeout);

// 释放资源
sop.sem_op = 1;
semop(semid, &sop, 1);

3. 条件同步:

// 等待条件满足(信号量为0)
sop.sem_op = 0;
semtimedop(semid, &sop, 1, &timeout);

总结

semtimedop 是一个功能强大的信号量操作函数,提供了:

1. 超时控制: 避免无限期等待,提高程序健壮性
2. 原子操作: 保证多信号量操作的原子性
3. 灵活配置: 支持多种操作标志和模式
4. 广泛应用: 适用于各种进程间同步场景

通过合理使用 semtimedop,可以构建更加可靠和高效的并发程序,特别是在需要精确时间控制的场景中表现出色。在实际应用中,需要注意超时设置、错误处理和资源管理等关键问题。

此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注