我有一个C程序,运行3个代码分支:2,我通过pthread_create和普通的启动。
我想知道如何正确地保护它,如果我的第二个线程未能创建不知何故。
下面是我的代码:
# include <pthread.h>
# include <stdio.h>
# include <stdlib.h>
# include <semaphore.h>
# include <errno.h>
typedef struct s_philo{
sem_t *first;
sem_t *second;
sem_t *stop_A;
sem_t *stop_B;
pthread_t A_thread;
pthread_t B_thread;
} t_philo;
void sem_close_safe(sem_t *sem)
{
if (sem_close(sem) == -1)
printf("Failed to close semaphore\n");
}
int free_philo(t_philo *philo)
{
if (philo->first)
sem_close_safe(philo->first);
if (philo->second)
sem_close_safe(philo->second);
if (philo->stop_A)
sem_close_safe(philo->stop_A);
if (philo->stop_B)
sem_close_safe(philo->stop_B);
free(philo);
return (1);
}
void *check_philo(t_philo *philo)
{
void *check;
check = philo;
if (!philo->first || !philo->second || !philo->stop_A || !philo->stop_B)
check = NULL;
return (check);
}
sem_t *sem_open_new_safe(const char *name, unsigned int value)
{
sem_t *sem;
sem = sem_open(name, O_CREAT | O_EXCL, 0644, value);
if (errno == EEXIST)
{
if (sem_unlink(name) == -1)
return (NULL);
sem = sem_open(name, O_CREAT | O_EXCL, 0644, value);
}
if (sem == SEM_FAILED)
return (NULL);
if (sem_unlink(name) == -1)
{
sem_close_safe(sem);
return (NULL);
}
return (sem);
}
void *A(void *p)
{
t_philo *philo;
philo = (t_philo *) p;
sem_wait(philo->stop_A);
sem_post(philo->stop_A);
return (NULL);
}
void *B(void *p)
{
t_philo *philo;
philo = (t_philo *) p;
sem_wait(philo->stop_B);
sem_post(philo->stop_B);
return (NULL);
}
int main(void)
{
t_philo *philo;
int i;
philo = malloc(sizeof(*philo));
philo->first = sem_open_new_safe("/first", 1);
philo->second = sem_open_new_safe("/second", 1);
philo->stop_A = sem_open_new_safe("/stop_A", 0);
philo->stop_B = sem_open_new_safe("/stop_B", 0);
if (!check_philo(philo))
return (free_philo(philo));
if (pthread_create(&philo->A_thread, NULL, &A, (void *)philo))
return (free_philo(philo));
if (pthread_create(&philo->B_thread, NULL, &B, (void *)philo))
return (free_philo(philo));
i = 0;
while (i++ < 100)
{
if (sem_wait(philo->first) == -1)
sem_post(philo->stop_B);
if (sem_wait(philo->second) == -1)
sem_post(philo->stop_A);
printf("%d\n", i);
sem_post(philo->second);
sem_post(philo->first);
}
sem_post(philo->stop_B);
sem_post(philo->stop_A);
pthread_join(philo->A_thread, NULL);
pthread_join(philo->B_thread, NULL);
free_philo(philo);
return (0);
}
我的A和B线程都在它们的第一行代码中等待信号量,因此如果我不发布这些信号量,它们将永远不会自己返回。
我应该pthread_join线程A吗?我应该手动发布一些信号量来强制线程A继续执行并返回吗?或者我应该使用pthread_detach吗?我有点迷路了。
编辑:我被要求发布更多的代码来使其可执行,但我有很多行代码,它只会淹没上面的一行。我正在寻找的(如果存在的话)不是一个指导性的特定于代码的答案,而是一个优雅地处理pthread_create错误的最佳实践。
编辑2:我添加了尽可能少的代码来使其可运行
2条答案
按热度按时间thtygnil1#
一般情况看起来像下面的伪代码:
你实际上是在问如何写
teardown_B()
。一般的 * 解决方案 *(假设你不能切换到C++来使用正确的析构函数和RAII)并不存在。拆卸就像设置一样,具体到A、B、C和你的应用程序的细节。
我想知道如何正确地保护它,如果我的第二个线程未能创建不知何故。
近似的答案是告诉线程退出(以某种特定于应用程序的方式),然后加入它。
请求关闭的实际语义取决于你的代码,因为你编写了线程正在执行的函数。这里,它应该足以让
sem_post
线程A
等待。注意:不要使用
pthread_kill
来关闭线程,如果你可以避免的话。最好明确地写干净的关闭处理。col17t5w2#
我想知道如何正确地保护它,如果我的第二个线程未能创建不知何故。
最简单的方法是在线程创建失败的情况下调用
exit(1)
,这将终止整个进程,包括它的所有线程,进程拥有的所有资源将被系统清理。如果程序想要清理任何持久性资源,比如文件或命名信号量,这确实会产生一个可能的问题。通常这不是一个主要问题,因为如果程序失败,那么它的终止可能比成功时不那么整齐。尽管如此,还是有办法减少这种影响。
特别是,你可以最小化程序对可修改的持久资源的使用。例如,如果你的程序使用 * 未命名的 * 信号量而不是命名的信号量,你的程序将是全面的清洁。当你创建它们时,你不需要注意现有的信号量,并且因为它们只在一个进程中使用,你不需要担心在终止之前无法清理它们。
但是如果您希望在程序终止时进行某种肯定的清理,您总是可以选择使用
atexit()
注册一个退出处理程序来执行此操作。虽然有一些警告,但最好了解此选项。我应该pthread_join线程A吗?
就你所举的例子而言,我认为没有理由这样做,在其他情况下,这样做可能更合适。
我是否应该手动发布一些信号量来强制线程A继续执行并返回?
如果你打算加入线程A,那么你需要确保它实际上会终止。在这种情况下,看起来是的,你可以通过信号量操作来实现这一点,但是在真正重要的情况下会更加复杂。在这种情况下,确保A的及时性可能不会那么简单。
或者也许我应该使用pthread_detach?
在这种情况下,这样做没有任何好处。线程A将在进程终止时终止,而不管它是否被分离。这大概就是您在示例中所希望的,因为如果它是进程中剩下的唯一活动线程,它将不会取得进展。