在Linux C应用编程中,多线程是一种常用的工作方式,用于提高应用的并发性和响应性。
为了满足线程间数据通讯、同步等需求,Linux C提供了互斥量和条件变量接口,来解决对于资源的竞态处理以及线程同步的功能。 对于互斥量和条件变量,优先选择标准C语言库中的实现,具有更好的跨平台兼容性,详细见文档如下所示。
本节中将进行互斥量和条件变量的说明。
互斥量功能说明
互斥量是一种同步机制,用于确保同一时间只有一个线程可以访问共享资源。对于Linux C应用中,互斥量的相关接口也位于pthread.h头文件中,通过pthread_mutex*系列函数来实现。
另外,对于互斥量来说说,还支持设置互斥量的类型,来改变互斥量的行为,通过pthread_mutexattr*系列函数来实现。另外这个系列中的pthread_mutexattr_settype和pthread_mutexattr_gettype函数,需要全局宏定义-D_XOPEN_SOURCE=600才能使用。
| |
|---|
pthread_mutex_init | |
pthread_mutex_lock | |
pthread_mutex_unlock | |
pthread_mutex_destroy | |
pthread_mutex_trylock | 尝试加锁,如果互斥量已被其他线程持有,则返回EBUSY,否则返回0 |
pthread_mutexattr_init | |
pthread_mutexattr_destroy | |
pthread_mutexattr_settype | |
pthread_mutexattr_gettype | |
对于上述接口,常用的函数说明如下所示。
// 初始化互斥量// @param __mutex 互斥量指针// @param __mutexattr 互斥量属性指针// @return 0 成功,-1 失败,设置errnointpthread_mutex_init(pthread_mutex_t *__mutex,constpthread_mutexattr_t *__mutexattr)// 互斥量加锁// @param __mutex 互斥量指针// @return 0 成功,-1 失败,设置errnointpthread_mutex_lock(pthread_mutex_t *__mutex)// 互斥量解锁// @param __mutex 互斥量指针// @return 0 成功,-1 失败,设置errnointpthread_mutex_unlock(pthread_mutex_t *__mutex)// 初始化互斥量属性// @param __attr 互斥量属性指针// @return 0 成功,-1 失败,设置errnointpthread_mutexattr_init(pthread_mutexattr_t *__attr);// 获取互斥量属性类型// @param __attr 互斥量属性指针// @param __kind 互斥量属性类型指针// @return 0 成功,-1 失败,设置errnointpthread_mutexattr_gettype(constpthread_mutexattr_t *__restrict __attr, int *__restrict __kind)// 设置互斥量属性类型// @param __attr 互斥量属性指针// @param __kind 互斥量属性类型// @return 0 成功,-1 失败,设置errnointpthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind);
对于互斥量属性类型配置,支持以下几种。
PTHREAD_MUTEX_NORMAL:普通互斥量,加锁时会阻塞其他线程,直到当前线程解锁。PTHREAD_MUTEX_RECURSIVE:递归互斥量,允许一个线程重复加锁,但是其他线程不能加锁。PTHREAD_MUTEX_ERRORCHECK:错误检查互斥量,加锁时会检查是否有其他线程正在解锁,如果有则返回EDEADLK。PTHREAD_MUTEX_DEFAULT:默认互斥量,与普通互斥量相同。
无特殊需求时,初始化时设置为普通互斥量即可。
条件变量功能说明
条件变量线程的同步机制,允许线程在特定条件未满足时挂起(进入睡眠状态),并在其他线程修改了该条件并发出信号后被唤醒。另外在设计上,条件变量支持超时自动唤醒功能,可以用于模拟类似软件定时器的操作。
| |
|---|
pthread_cond_init | |
pthread_cond_destroy | |
pthread_cond_wait | |
pthread_cond_timedwait | |
pthread_cond_signal | |
pthread_condattr_init | |
pthread_condattr_destroy | |
pthread_condattr_getclock | |
pthread_condattr_setclock | |
对于上述接口,常用的函数说明如下所示。
// 初始化条件变量// @param __cond 条件变量指针// @param __cond_attr 条件变量属性指针// @return 0 成功,-1 失败,设置errnointpthread_cond_init(pthread_cond_t *__restrict __cond, constpthread_condattr_t *__restrict __cond_attr)// 触发条件变量// @param __cond 条件变量指针// @return 0 成功,-1 失败,设置errnointpthread_cond_signal(pthread_cond_t *__cond)// 等待条件变量// @param __cond 条件变量指针// @param __mutex 互斥量指针// @return 0 成功,-1 失败,设置errnointpthread_cond_wait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex)// 带超时等待条件变量// @param __cond 条件变量指针// @param __mutex 互斥量指针// @param __abstime 超时时间指针// @return 0 成功,-1 失败,设置errnointpthread_cond_timedwait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex, const struct timespec *__restrict __abstime)// 初始化条件变量属性// @param __attr 条件变量属性指针// @return 0 成功,-1 失败,设置errnointpthread_condattr_init(pthread_condattr_t *__attr)// 获取条件变量属性中的时钟特性// @param __attr 条件变量属性指针// @param __clock_id 时钟特性指针// @return 0 成功,-1 失败,设置errnointpthread_condattr_getclock(constpthread_condattr_t * __restrict __attr, __clockid_t *__restrict __clock_id)// 设置条件变量属性中的时钟特性// @param __attr 条件变量属性指针// @param __clock_id 时钟特性// @return 0 成功,-1 失败,设置errnointpthread_condattr_setclock(pthread_condattr_t *__attr, __clockid_t __clock_id)
对于条件变量属性时钟特性配置,支持以下几种。
CLOCK_REALTIME:使用实时时钟,会随着系统时间变化而变化(修改系统时间会导致条件变量超时变化,不建议使用)CLOCK_MONOTONIC:使用单调时钟,不会因为系统时间变化而变化。
互斥量、条件变量应用示例
关于互斥量、条件变量应用示例如下。
//////////////////////////////////////////////////////////////////////////////// (c) copyright 2025-by Persion Inc. // All Rights Reserved//// Name:// main.c//// Purpose:// Linux C线程管理应用示例//// Author:// @公众号:<嵌入式技术总结>//// Revision History:// /////////////////////////////////////////////////////////////////////////////#include<stdio.h>#include<stdlib.h>#include<pthread.h>#include<errno.h>#include<unistd.h>#include<sys/time.h>#include<time.h>staticvolatileint g_i = 0;staticpthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;// 互斥量的应用void *thread_mutex_process(void *arg){for (int i = 0; i < 1000; i++) { pthread_mutex_lock(&g_mutex); g_i++; pthread_mutex_unlock(&g_mutex); }// 退出线程,返回结果值// 此处强制转换为指针作为返回值 pthread_exit((int *)g_i);}// 条件变量的释放void *thread_condition_tx(void *arg){// 延时等待确保接收线程启动完成 usleep(100000);// 发送10个信号量for (int i = 0; i < 10; i++) { pthread_cond_signal(&g_cond); usleep(500000); } pthread_exit(NULL);}// 条件变量的接收void *thread_condition_rx(void *arg){structtimespects;int timeout_count = 0;int rx_count = 0;while(1) { clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec += 1; pthread_mutex_lock(&g_mutex);int status = pthread_cond_timedwait(&g_cond, &g_mutex, &ts); pthread_mutex_unlock(&g_mutex);if(status == 0) { rx_count++;printf("thread_condition_rx:%d\n", rx_count); } elseif(status == ETIMEDOUT) { timeout_count++;printf("thread_condition_rx timeout: %d\n", timeout_count); } else {printf("thread_condition_rx error: %d\n", status); } }}intmain(int argc, char *argv[]){pthread_t tid[10];pthread_mutexattr_t mutex_attr; pthread_mutexattr_init(&mutex_attr); pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&g_mutex, &mutex_attr);// 创建线程for (int i = 0; i < 10; i++) {if (pthread_create(&tid[i], NULL, thread_mutex_process, NULL) != 0) {printf("pthread_create error\n");exit(-1); } }// 等待所有线程完成for (int i = 0; i < 10; i++){ pthread_join(tid[i], NULL); }printf("result g_i: %d\n", g_i);// 创建条件变量和应用pthread_condattr_t cond_attr; pthread_condattr_init(&cond_attr); pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); pthread_cond_init(&g_cond, &cond_attr);pthread_t tx_tid, rx_tid; pthread_create(&tx_tid, NULL, thread_condition_tx, NULL); pthread_create(&rx_tid, NULL, thread_condition_rx, NULL); pthread_join(tx_tid, NULL); pthread_join(rx_tid, NULL);// 销毁条件变量和互斥锁 pthread_cond_destroy(&g_cond); pthread_mutex_destroy(&g_mutex);return0;}
关于上述应用示例,执行的结果如下。

总结说明
互斥量提供了一种线程安全的数据访问方式,通过使用互斥量,可以避免数据竞争,从而保证程序的正确性和安全性。
条件变量,则提供了一个线程间同步机制,可以确保在条件变量满足时,线程才被唤醒执行,其它时间被堵塞而不占用CPU资源。
条件变量和互斥量是多线程编程的基础,这里主要从Linux C接口应用部分阐述相关接口的功能和应用,对于理解C标准库中的线斥量和条件变量接口也有一定帮助,可以互相印证提高。