引自免费微信小程序:皆我百晓生
这是一个使用POSIX线程(pthread)和互斥锁(mutex)的C++多线程并发程序示例。你的代码中有一些问题和潜在的改进点。让我们一步步地解决它们。
问题和解决方案:
- 线程函数中死循环问题:你的
print
函数是一个死循环,这意味着线程会一直运行下去,除非被某种方式中断。这可能导致你的程序永远不会结束。通常,你需要一种方法来让线程在完成任务后退出。在这个例子中,你可以使用pthread_exit()
来结束线程。但更好的做法是在循环中使用一个标志变量来检查是否应该退出。 - 互斥锁的使用问题:你在解锁时使用了
netx(n)
函数的结果作为互斥锁的索引,这可能不是你想要的。因为该函数可能会导致解锁的互斥锁不是线程加锁的同一个互斥锁。你应该确保解锁的是线程自己加锁的互斥锁。 - 主线程退出问题:在主函数中,你设置了一个闹钟(使用
alarm(5)
),但没有处理SIGALRM信号。因此,当闹钟到期时,程序会默认终止,而不是按预期执行其他操作。你可能需要处理这个信号或者删除这个部分。
基于上述问题,让我们对代码进行一些修改:
修改后的代码:
#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#include <signal.h> // 为了处理SIGALRM信号
pthread_mutex_t mymutex[3];
bool should_exit = false; // 用于控制线程退出的标志变量
void signal_handler(int signum) { // 处理SIGALRM信号的函数
if (signum == SIGALRM) {
should_exit = true; // 设置标志变量以退出线程
}
}
void* print(void* p) {
int n = (long)p;
int ch = 'a' + n;
while (!should_exit) { // 使用标志变量控制循环
pthread_mutex_lock(mymutex + n); // 加锁
write(STDOUT_FILENO, &ch, 1); // 使用STDOUT_FILENO代替数字1来写入标准输出,避免平台依赖性问题
pthread_mutex_unlock(mymutex + n); // 解锁对应的互斥锁,而不是netx(n)的结果
usleep(1000); // 添加延时以模拟工作负载(可选)
}
return NULL; // 正常退出线程
}
int main() {
pthread_t tid[3];
int ret = 0;
signal(SIGALRM, signal_handler); // 注册信号处理器来处理SIGALRM信号
for (int i = 0; i < 3; ++i) {
pthread_mutex_init(mymutex + i, NULL); // 初始化互斥锁
pthread_mutex_lock(mymutex + i); // 在创建线程之前锁定互斥锁(可选)以避免竞争条件在初始化阶段发生。但这通常不是必要的。注意这里不需要再解锁了。直接创建线程即可。 ret = pthread_create(&tid[i], NULL, print, (void*)i); // 创建线程而不立即解锁互斥锁以避免竞态条件(可选)如果删除这一行中的解锁操作,那么在创建线程之前不必加锁了。 if (ret) { fprintf(stderr, "create false"); return 1; } } alarm(5); // 设置闹钟以在5秒后触发SIGALRM信号 for (int i = 0; i < 3; ++i) { pthread_mutex_destroy(mymutex + i); // 在主线程退出之前销毁互斥锁是必要的,否则会造成资源泄漏 pthread_join(tid[i], NULL); // 主线程等待子线程结束 } return 0;}``` 在这个修改后的代码中,我添加了一个标志变量来控制线程的循环,并注册了一个信号处理函数来处理SIGALRM信号。这样,当闹钟到期时,主线程可以设置标志变量来通知所有工作线程退出。另外,我也使用了`usleep()`函数来模拟每个线程的工作负载(这取决于你的实际需求)。注意:在使用多线程编程时,还需要考虑数据共享和同步的问题以及潜在的竞态条件等问题,这取决于你的实际需求和环境设置来适当修改和优化代码。希望这可以帮助你解决问题!如果你有其他关于代码的问题或需要进一步的解释,请告诉我!