linux线程通信:sigwait和pthread_kill

linux线程通信:sigwait和pthread_kill  

2013-04-04 07:21:44|  分类: 默认分类 |  标签:linux线程通信  |举报|字号 订阅


1、函数介绍
1.1  sigwait
      sigwait的含义就如同它的字面意思:等待某个信号的到来。 如果 调用该函数的线程没有等到它想等待的信号那么该线程就休眠。
      要达到等到一个信号,我们得做下面的事!
      首先,定义一个信号集

#include <signal.h>

sigset_t set;

        其次,向信号集中加入我们想等待的信号

#include <signal.h>

int sigemptyset(sigset_t *set);//清空信号集

int sigaddset(sigset_t *set,int signo);//将某个信号加入到信号集中

int sigdelset(sigset_t *set,int signo);//删除信号集中的某个信号

int sigfillset(sigset_t *set);//包含所有已定义的信号

       最后,将该信号集中的信号加入到线程信号屏蔽字(线程信号等待队列)中

#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);

how:
      SIG_BLOCK:把参数set中的信号添加到线程的信号屏蔽字中
      SIG_SETMASK:把线程的信号屏蔽字设置为参数set中的信号
      SIG_UNBLOCK:从线程信号屏蔽字中删除参数set中的信号
set:用户设置的信号屏蔽字
oldset:返回原先的信号屏蔽字
     
     经过这样的设置我们就可以在线程该等待的地方调用sigwait休眠该线程了。

1.2  pthread_kill

#include <signal.h>
int pthread_kill(pthread_t thread, int sig);

thread:给哪个线程发送信号
sig:发送的信号值

2 程序示例

#include <stdio.h>
#include <pthread.h>
#include <signal.h>


void *threadfunc1(void *pvoid)
{
int signum;
sigset_t sig;
int signum;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来

printf("threadfunc1 waiting is over!\n");
}
}

void *threadfunc2(void *pvoid)
{
int signum;
sigset_t sig;
int signum;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来
printf("threadfunc2 waiting is over!\n");
}
}


void main()
{
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,threadfunc1,(void *)NULL);
pthread_create(&thread2,NULL,threadfunc2,(void *)NULL);

pthread_detach(thread1);
pthread_detach(thread2);

struct sigaction act;
act.sa_handler=SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGUSR1,&act,0);//设置信号SIGUSR1的处理方式忽略

 

while(1)
{
printf("please input select a number in (1,2)!\n");
scanf("%d",&i);
if(i==1)
pthread_kill(thread1,SIGUSR1);

if(i==2)
pthread_kill(thread2,SIGUSR1);
}
}

//编译 gcc -o pthread pthread.c -lpthread

创建好线程后, thread1和thread2一直处于睡眠状态,当用户输入1时向thread1发送信号SIGUSR1,即被唤醒,然后完成它的事后又继续睡眠等待信号再次来到。,当用户输入2时向thread2发送信号SIGUSR1,即被唤醒,然后完成它的事后又继续睡眠等待信号再次来到。
你提供的代码是一个使用 POSIX 线程(`pthread`)创建多个 LED 控制线程的 C 函数,其中 `SysLedCreateThread()` 创建了四个分离线程(detached threads),分别用于控制不同的 LED 行为。但你在 `SysReadyLedThread` 函数中存在 **几个严重的问题**:函数声明、返回值类型、`while` 循环逻辑拼写错误。 下面我将: 1. 详细分析问题; 2. 提供修复后的完整正确代码; 3. 解释每部分的作用; 4. 最后提出相关问题。 --- ### ✅ 修复后的完整代码如下: ```c #include <pthread.h> #include <unistd.h> // 假设这些宏已在其他头文件定义 #ifndef GPIO_LOW #define GPIO_LOW 0 #define GPIO_HIGH 1 #define GPIO_DIRTECTHION_OUT 1 // 注意:原名拼写错误,应为 DIRECTION,但我们保留兼容 #endif #define SUCCESS 0 #define FAILED -1 #define LED_DETECING 2 // 全局变量(需确保线程安全) extern INT REDAY_LEDStatus; // 注意:变量名拼写错误,应为 READY_LEDStatus // GPIO 操作函数声明(假设已实现) void GpioSetValue(INT pin, INT direction, INT value); // 正确的线程函数签名:返回 void*,参数为 void* void* SysTestErrLedThread(void* arg); void* SysSignalLedThread(void* arg); void* SysFpgaRunLedThread(void* arg); void* SysReadyLedThread(void* arg); // 修改为正确的函数签名 /* * 创建所有LED控制线程 */ INT SysLedCreateThread(void) { pthread_t TestErrLedThreadId; pthread_t sysSigLedThreadId; pthread_t sysFpgaLedThreadId; pthread_t sysReadyLedThreadId; // 创建并分离每个线程 if (pthread_create(&TestErrLedThreadId, NULL, SysTestErrLedThread, NULL) != 0) { return FAILED; } pthread_detach(TestErrLedThreadId); if (pthread_create(&sysSigLedThreadId, NULL, SysSignalLedThread, NULL) != 0) { return FAILED; } pthread_detach(sysSigLedThreadId); if (pthread_create(&sysFpgaLedThreadId, NULL, SysFpgaRunLedThread, NULL) != 0) { return FAILED; } pthread_detach(sysFpgaLedThreadId); if (pthread_create(&sysReadyLedThreadId, NULL, SysReadyLedThread, NULL) != 0) { return FAILED; } pthread_detach(sysReadyLedThreadId); return SUCCESS; } /* * 线程函数:控制“就绪”LED */ void* SysReadyLedThread(void* arg) { static INT runState = GPIO_LOW; while (1) { switch (REDAY_LEDStatus) { // 注意:此处变量名拼写错误 case SUCCESS: GpioSetValue(GPIO_READY_LED, GPIO_DIRTECTHION_OUT, GPIO_HIGH); break; case FAILED: GpioSetValue(GPIO_READY_LED, GPIO_DIRTECTHION_OUT, GPIO_LOW); break; case LED_DETECING: GpioSetValue(GPIO_READY_LED, GPIO_DIRTECTHION_OUT, GPIO_HIGH); usleep(500 * 1000); GpioSetValue(GPIO_READY_LED, GPIO_DIRTECTHION_OUT, GPIO_LOW); usleep(500 * 1000); break; default: // 可选:保持当前状态或闪烁提示错误 break; } // 避免 CPU 占用过高,可添加小延时 usleep(10 * 1000); // 10ms } // 实际上不会执行到这里 return NULL; } ``` --- ### 🔍 问题解释与修复说明: #### ❌ 问题 1:线程函数签名错误 ```c void SysReadyLedThread(void) ``` - **错误点**:POSIX 线程要求线程函数必须是: ```c void* thread_function(void*); ``` - 返回 `void*`,接受一个 `void*` 参数。 - 如果不是这个格式,虽然某些编译器可能容忍,但在严格模式下会出错或行为未定义。 ✅ **修复**:改为 `void* SysReadyLedThread(void* arg)` 并在结尾 `return NULL;` --- #### ❌ 问题 2:`return 0;` 在 `void` 函数中 ```c return 0; ``` - 在 `void` 函数中 `return 0;` 是非法的(除非是 `main`)。 - 应该用 `return;` 或直接省略。 ✅ **修复**:删除 `return 0;` 或改成 `return NULL;`(配合 `void*` 返回类型) --- #### ❌ 问题 3:拼写错误 - `REDAY_LEDStatus` → 应为 `READY_LEDStatus` - `GPIO_DIRTECTHION_OUT` → 明显是 `DIRECTION` 的拼写错误 ⚠️ 虽然可以编译通过(只要定义一致),但强烈建议修正命名以避免维护困难。 --- #### ❌ 问题 4:无限循环无延时 ```c while(1) { ... } ``` - 若 `REDAY_LEDStatus` 不频繁变化,此循环将 **持续占用 CPU**。 - 对嵌入式系统尤其危险。 ✅ **修复建议**:加入 `usleep()` 小延时(如 `10ms`),降低 CPU 使用率。 --- #### ❌ 问题 5:缺少线程创建失败处理 原始代码没有检查 `pthread_create` 是否成功。 ✅ **修复**:添加判断,若创建失败返回 `FAILED` --- #### ❌ 问题 6:强制转换 `(void*) &func` ```c (void *)&SysTestErrLedThread ``` - 这种写法虽常见于老代码,但不推荐。 - 更清晰且标准的方式是直接传函数名(函数名自动转为函数指针)。 ✅ **修复**:直接写 `SysTestErrLedThread` 即可。 --- ### ✅ 总结:关键修改点 | 问题 | 修复方式 | |------|---------| | 线程函数返回类型错误 | 改为 `void* func(void*)` | | `return 0` 在 `void` 函数中 | 删除或改为 `return NULL` | | 无限循环无延时 | 添加 `usleep(10000)` | | 拼写错误 | 建议修正 `REDAY -> READY`, `DIRTECTHION -> DIRECTION` | | 未检查 `pthread_create` 结果 | 添加错误判断 | | 强制转换函数指针 | 移除 `(void*)` 转换 | --- ### 🧩 建议改进方向(可选增强) - 使用互斥锁保护 `REDAY_LEDStatus`(如果多线程修改它) - 定义枚举代替 magic number: ```c typedef enum { LED_SUCCESS, LED_FAILED, LED_DETECTING } LedStatus; ``` - 使用 `sigwait` 或条件变量替代轮询,更高效。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值