Ubuntu下C语言线程信号量实现数学运算的报错解决
问题描述
在Ubuntu上学习线程和信号量的C语言编程,目标是实现一个包含加法、乘法的数学运算程序,要求P4函数最后执行。已声明互斥信号量mutex和信号量prive,编写了P1-P4四个函数,但编译出现两类错误:
pthread_create参数类型不兼容- P3函数声明与定义类型冲突
同时希望程序支持用户输入两个变量再执行运算。
原始代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> void *P1(void *arg, int A, int B); void *P2(void *arg, int A); void *P3(void *arg, int S1, int S2); void *P4(void *arg, int S3, int S2); sem_t mutex, prive; int S1 = 0, S2 = 0, S3 = 0, S4 = 0; int A = 15; int B = 10; int main(){ pthread_t TID1, TID2, TID3, TID4; printf("Main: "); sem_init(&mutex, 0, 1); sem_init(&prive, 0, 0); pthread_create(&TID1, NULL, P1, NULL); pthread_create(&TID2, NULL, P2, NULL); pthread_create(&TID3, NULL, P3, NULL); pthread_create(&TID4, NULL, P4, NULL); pthread_join(TID1, NULL); pthread_join(TID2, NULL); pthread_join(TID3, NULL); pthread_join(TID4, NULL); sem_destroy(&mutex); sem_destroy(&prive); printf("S4= %d", S4); } void *P1(void *arg, int A, int B){ sem_wait(&mutex); S1 = A + B; printf("S1= %d", S1); sem_post(&prive); pthread_exit(NULL); } void *P2(void *arg, int A){ sem_wait(&mutex); S2 = A + 4; printf("S2= %d", S2); sem_post(&prive); pthread_exit(NULL); } void *P3(void *arg, int S2){ sem_wait(&mutex); S3 = S2 * 2; sem_post(&prive); pthread_exit(NULL); } void *P4(void *arg, int S3, int S2){ sem_wait(&prive); sem_wait(&prive); S4 = S2 + S3; sem_post(&mutex); sem_post(&mutex); pthread_exit(NULL); }
编译报错信息
错误1:pthread_create参数类型不兼容
TP4_EXO3.c: 在函数‘main’中:
TP4_EXO3.c:24:1: 警告:传递‘pthread_create’的参数3时类型不兼容 [默认启用]
pthread_create(&TID1, NULL, P1, NULL);
^
从TP4_EXO3.c:3:0包含的文件:
/usr/include/pthread.h:244:12: 附注:期望‘void * (*)(void )’但实参的类型为‘void * ()(void *, int, int)’
extern int pthread_create (pthread_t *__restrict __newthread, //TID2、TID3、TID4同理//
^
错误2:P3函数类型冲突
TP4_EXO3.c: 在顶层:
TP4_EXO3.c:57:7: 错误:‘P3’的类型冲突
void *P3(void *arg, int S2){
^
TP4_EXO3.c:8:7: 附注:‘P3’的先前声明在此
void *P3(void *arg, int S1, int S2);
^
问题解决与代码修正
1. 修复pthread_create参数类型问题
pthread_create要求线程函数必须是void *(*)(void *)类型,即仅接受一个void*参数,返回void*。原代码中线程函数额外添加了int参数,不符合要求。
解决方式:利用全局变量直接访问运算所需的A、B、S1、S2等变量,无需额外传参,将所有线程函数的声明和定义修改为仅接受void* arg参数。
2. 修复P3函数声明与定义冲突
原代码中P3的声明为void *P3(void *arg, int S1, int S2);,但定义仅接受两个参数,参数数量不匹配。根据代码逻辑,P3仅使用S2计算S3,因此修正P3的声明为void *P3(void *arg);。
3. 添加用户输入功能
在main函数开头添加scanf语句,让用户输入A和B的值,替换原有的固定赋值。
4. 修正信号量逻辑确保P4最后执行
原信号量逻辑无法保证P4在P1、P2、P3全部完成后执行。调整为:
- 将
prive信号量初始值设为0 - P1、P2、P3执行完成后各调用一次
sem_post(&prive),累计发出3个信号 - P4中调用三次
sem_wait(&prive),等待所有前置任务完成后再执行
同时修正P4中错误的sem_post(&mutex)调用(P4未获取mutex,无需释放)。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> // 符合pthread要求的线程函数声明 void *P1(void *arg); void *P2(void *arg); void *P3(void *arg); void *P4(void *arg); sem_t mutex, prive; int S1 = 0, S2 = 0, S3 = 0, S4 = 0; int A, B; // 等待用户输入 int main(){ pthread_t TID1, TID2, TID3, TID4; // 获取用户输入 printf("请输入两个整数A和B:"); scanf("%d %d", &A, &B); // 初始化信号量:mutex初始为1(互斥锁),prive初始为0(等待前置任务完成) sem_init(&mutex, 0, 1); sem_init(&prive, 0, 0); // 创建线程 pthread_create(&TID1, NULL, P1, NULL); pthread_create(&TID2, NULL, P2, NULL); pthread_create(&TID3, NULL, P3, NULL); pthread_create(&TID4, NULL, P4, NULL); // 等待所有线程结束 pthread_join(TID1, NULL); pthread_join(TID2, NULL); pthread_join(TID3, NULL); pthread_join(TID4, NULL); // 销毁信号量 sem_destroy(&mutex); sem_destroy(&prive); printf("\n最终结果:S4= %d\n", S4); return 0; } void *P1(void *arg){ sem_wait(&mutex); // 获取互斥锁,保护全局变量 S1 = A + B; printf("S1= %d\n", S1); sem_post(&mutex); // 释放互斥锁 sem_post(&prive); // 通知P4任务完成 pthread_exit(NULL); } void *P2(void *arg){ sem_wait(&mutex); S2 = A + 4; printf("S2= %d\n", S2); sem_post(&mutex); sem_post(&prive); pthread_exit(NULL); } void *P3(void *arg){ sem_wait(&mutex); S3 = S2 * 2; printf("S3= %d\n", S3); sem_post(&mutex); sem_post(&prive); pthread_exit(NULL); } void *P4(void *arg){ // 等待P1、P2、P3全部完成 sem_wait(&prive); sem_wait(&prive); sem_wait(&prive); S4 = S2 + S3; pthread_exit(NULL); }
编译与运行
使用以下命令编译(必须链接pthread库):
gcc TP4_EXO3.c -o TP4_EXO3 -lpthread
运行程序后输入两个整数,即可看到各步骤结果及最终S4的值。
内容的提问来源于stack exchange,提问作者MohaSetif

