菜单

Cobalt/Semaphores

详细描述

Cobalt/POSIX 信号量服务。

信号量是在线程之间共享资源的计数器。信号量的基本操作是:原子性地增加计数器,以及等待计数器为非零并原子性地减少它。

信号量有一个最大值,超过该值后不能再增加。宏 SEM_VALUE_MAX 被定义为此最大值。


函数文档

sem_close()

int sem_close (sem_t *sem)

关闭命名信号量。

此服务关闭信号量 sem。信号量仅在调用 sem_unlink() 服务取消链接并且每次调用 sem_open() 都匹配一次此服务调用时才会被销毁。

当信号量被销毁时,它使用的内存将返回到系统堆,因此进一步引用此信号量不保证失败,这与未命名信号量的情况相同。

如果 sem 是未命名信号量,则此服务将失败。

参数:

  • sem: 要关闭的信号量。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • EINVAL,信号量 sem 无效或是未命名信号量。

标签:

  • thread-unrestrictedswitch-secondary

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建信号量,初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

sem_destroy()

int sem_destroy (sem_t *sem)

销毁未命名信号量。

此服务销毁信号量 sem。当前阻塞在 sem 上的线程将被解除阻塞,并且它们调用的服务将返回 -1,并将 errno 设置为 EINVAL。然后,信号量被所有信号量服务视为无效(它们都将失败并将 errno 设置为 EINVAL),除了 sem_init()

如果 sem 是命名信号量,则此服务将失败。

参数:

  • sem: 要销毁的信号量。

返回值:

  • 成功时总是返回 0

    • 如果在 sem_init_np() 中提到了 SEM_WARNDEL,则信号量按请求删除,并返回一个严格的正值以警告调用者是否有线程在等待,否则返回零。
    • 如果在 sem_init_np() 中提到了 SEM_NOBUSYDEL,则 sem_destroy() 仅在没有线程等待信号量删除时才可能成功;否则返回 -EBUSY
  • 如果出错,返回 -1 并设置 errno

    • EINVAL: 信号量 sem 无效或是命名信号量;
    • EPERM: 信号量 sem 是进程共享的,并且不属于当前进程;
    • EBUSY: 当前有线程在信号量 sem 上等待,并且设置了 SEM_NOBUSYDEL

标签:

  • thread-unrestricted

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define NUM_THREADS 5

sem_t semaphore;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(&semaphore);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(&semaphore);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 初始化信号量,初始值为2(表示可以有两个线程进入临界区)
    if (sem_init(&semaphore, 0, 2) != 0) {
        perror("sem_init failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 销毁信号量
    if (sem_destroy(&semaphore) != 0) {
        perror("sem_destroy failed");
    }

    return 0;
}

sem_init()

int sem_init (sem_t *sem, int pshared, unsigned int value)

初始化未命名信号量。

此服务初始化信号量 sem,初始值为 value

如果 sem 已经初始化或是命名信号量,则此服务将失败。

参数:

  • sem: 要初始化的信号量。
  • pshared: 如果为零,表示新信号量只能被调用 sem_init() 的线程所在的同一进程中的线程使用;如果为非零,表示新信号量可以被任何有权访问信号量所在内存的线程使用。
  • value: 信号量的初始值。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • EBUSY: 信号量 sem 已经初始化;
    • EAGAIN: 初始化信号量的内存不足,对于进程共享信号量,请增加 CONFIG_XENO_OPT_SHARED_HEAPSZ,对于进程私有信号量,请增加 CONFIG_XENO_OPT_PRIVATE_HEAPSZ
    • EAGAIN: 没有可用的注册槽,请检查/增加 CONFIG_XENO_OPT_REGISTRY_NRSLOTS
    • EINVAL: 参数 value 超过 SEM_VALUE_MAX

标签:

  • thread-unrestricted

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define NUM_THREADS 5

sem_t semaphore;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(&semaphore);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(&semaphore);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 初始化信号量,初始值为2(表示可以有两个线程进入临界区)
    if (sem_init(&semaphore, 0, 2) != 0) {
        perror("sem_init failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 销毁信号量
    if (sem_destroy(&semaphore) != 0) {
        perror("sem_destroy failed");
    }

    return 0;
}

sem_post()

int sem_post (sem_t *sem)

释放信号量。

此服务释放信号量 sem

如果当前没有线程阻塞在此信号量上,并且未启用“脉冲”模式(参见 sem_init_np()SEM_PULSE),则其计数将增加。如果有线程阻塞在信号量上,则等待队列中的第一个线程将被解除阻塞。

参数:

  • sem: 要释放的信号量。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • EINVAL: 指定的信号量无效或未初始化;
    • EPERM: 信号量 sem 不是进程共享的,并且不属于当前进程;
    • EAGAIN: 信号量计数已达到 SEM_VALUE_MAX

标签:

  • unrestricted

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建信号量,初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

sem_trywait()

int sem_trywait (sem_t *sem)

尝试减少信号量。

此服务等同于 sem_wait(),但如果信号量 sem 当前已耗尽,它会立即返回,并且它不是一个取消点。

参数:

  • sem: 要减少的信号量。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • EINVAL: 指定的信号量无效或未初始化;
    • EPERM: 信号量 sem 不是进程共享的,并且不属于当前进程;
    • EAGAIN: 指定的信号量当前已完全耗尽。

标签:

  • xthread-only

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    while(sem_trywait(sem) != 0) {
        sleep(1);
    }
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建信号量,初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

sem_unlink()

int sem_unlink (const char *name)

取消命名信号量的链接。

此服务取消名为 name 的信号量的链接。该信号量在通过调用 sem_close() 关闭所有通过 sem_open() 获取的引用之前不会被销毁。然而,取消链接的信号量将无法再通过 sem_open() 服务访问。

当信号量被销毁时,它使用的内存将返回到系统堆,因此进一步引用此信号量不保证失败,这与未命名信号量的情况相同。

参数:

  • name: 要取消链接的信号量的名称。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • ENAMETOOLONG: name 参数的长度超过 64 个字符;
    • ENOENT: 指定名称的信号量不存在。

标签:

  • thread-unrestrictedswitch-secondary

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建信号量,初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

sem_wait()

int sem_wait(sem_t *sem)

减少信号量。

此服务在信号量 sem 的当前值大于 0 时减少其值。如果信号量的当前值为零,则调用线程将被挂起,直到信号量被释放,或者一个信号被传递给调用线程。

对于通过 pthread_create() 服务创建的 Cobalt 线程,此服务是一个取消点。当这样的线程在调用此服务时被取消时,在调用取消清理处理程序之前,信号量状态保持不变。

参数:

  • sem: 要减少的信号量。

返回值:

  • 成功时返回 0
  • 出错时返回 -1 并设置 errno
    • EPERM: 调用者上下文无效;
    • EINVAL: 信号量无效或未初始化;
    • EPERM: 信号量 sem 不是进程共享的,并且不属于当前进程;
    • EINTR: 调用者在此服务中被信号中断。

标签:

  • xthread-onlyswitch-primary

示例代码

c{filename="app.c"} 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>

#define NUM_THREADS 5
#define SEM_NAME "/my_semaphore"

sem_t *sem;

void *thread_function(void *arg) {
    int thread_id = *((int *)arg);
    
    // 请求访问信号量
    sem_wait(sem);
    
    // 访问共享资源
    printf("Thread %d: has entered the critical section.\n", thread_id);
    sleep(1);  // 模拟对共享资源的处理
    printf("Thread %d: is leaving the critical section.\n", thread_id);
    
    // 释放信号量
    sem_post(sem);
    
    return NULL;
}

int main() {
    pthread_t threads[NUM_THREADS];
    int thread_ids[NUM_THREADS];

    // 创建信号量,初始值为1
    sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    // 创建多个线程
    for (int i = 0; i < NUM_THREADS; i++) {
        thread_ids[i] = i + 1;
        pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]);
    }

    // 等待所有线程完成
    for (int i = 0; i < NUM_THREADS; i++) {
        pthread_join(threads[i], NULL);
    }

    // 关闭信号量
    if (sem_close(sem) == -1) {
        perror("sem_close failed");
    }
    
    // 删除信号量
    if (sem_unlink(SEM_NAME) == -1) {
        perror("sem_unlink failed");
    }

    return 0;
}

最近修改: 2025-07-24