"Train crossing mutex problem" - 最后两行为 NULL
"Train crossing mutex problem" - Getting NULL on last 2 lines
嘿,我在解决导致一些不需要的 NULL 显示在我的最终输出中的错误时遇到了问题。当您 运行 程序在 运行ning 之前在命令行中输入一个字符串,例如 'nnseeeewwwew'。
这是代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
/* mutex */
pthread_mutex_t thisMutex;
/* Condition Variables */
sem_t nQueue, eQueue, sQueue, wQueue;
int nFirst, sFirst, eFirst, wFirst;
int done = 0;
/* Thread Prototypes */
void *bats(void *);
void *checking(void *);
/* Prototypes */
void arrive(int num, char *dir);
void cross();
void leave(int num, char *dir);
void check();
/* Global pointer to argv */
char *directions = NULL;
int main(int argc, char *argv[])
{
int i = 0,
n = 0,
s = 0,
e = 0,
w = 0;
directions = argv[1];
while( argv[1][i] == 'n' || argv[1][i] == 'e' ||
argv[1][i] == 's' || argv[1][i] == 'w' )
{
if(argv[1][i] == 'n'){n++;}
if(argv[1][i] == 's'){s++;}
if(argv[1][i] == 'e'){e++;}
if(argv[1][i] == 'w'){w++;}
i++;
}
pthread_mutex_init(&thisMutex, NULL);
sem_init(&nQueue, 0, n);
sem_init(&sQueue, 0, s);
sem_init(&eQueue, 0, e);
sem_init(&wQueue, 0, w);
nFirst = sFirst = eFirst = wFirst = 0;
pthread_t tid[i];
pthread_t checker;
pthread_create(&checker, NULL, checking, NULL);
for(int j = 0; j < i; j++)
{ pthread_create(&tid[j], NULL, bats, (void*) &j); }
for(int j = 0; j < i; j++)
{ pthread_join(tid[j], NULL); }
done = 1;
pthread_join(checker, NULL);
pthread_mutex_destroy(&thisMutex);
sem_destroy(&nQueue);
sem_destroy(&sQueue);
sem_destroy(&wQueue);
sem_destroy(&eQueue);
return 0;
}
void *checking(void *arg)
{
while( done == 0 )
{
if( nFirst == 1 || sFirst == 1 ||
eFirst == 1 || wFirst == 1 )
check();
}
exit(0);
}
void *bats(void *arg)
{
int index = *(int *)arg;
char *dir;
switch (directions[index])
{
case 'n':
dir = "North";
break;
case 's':
dir = "South";
break;
case 'e':
dir = "East";
break;
case'w':
dir = "West";
break;
}
arrive(index, dir);
leave(index, dir);
_exit(0);
}
/* Functions */
void arrive(int num, char *dir)
{
printf("BAT %d from %s arrives at crossing\n", num, dir);
if(strcmp(dir,"North")== 0)
{
sem_wait(&nQueue);
nFirst = 1;
while(eFirst == 1){ /* do nothing */ }
cross();
nFirst = 0;
sem_post(&nQueue);
}
else if(strcmp(dir,"West")== 0)
{
sem_wait(&wQueue);
wFirst = 1;
while(nFirst == 1){ /* do nothing */ }
cross();
wFirst = 0;
sem_post(&wQueue);
}
else if(strcmp(dir,"South")== 0)
{
sem_wait(&sQueue);
sFirst = 1;
while(wFirst == 1){ /* do nothing */ }
cross();
sFirst = 0;
sem_post(&sQueue);
}
else if(strcmp(dir,"East")== 0)
{
sem_wait(&eQueue);
eFirst = 1;
while(sFirst == 1){ /* do nothing */ }
cross();
eFirst= 0;
sem_post(&eQueue);
}
}
void cross()
{
pthread_mutex_lock(&thisMutex);
sleep(1);
pthread_mutex_unlock(&thisMutex);;
}
void leave(int num, char *dir)
{
printf("BAT %d from %s leaving crossing\n", num, dir);
}
void check()
{
if( nFirst == 1 && sFirst == 1 &&
eFirst == 1 && wFirst == 1 )
{
eFirst = 0;
sleep(1);
eFirst = 1;
}
}
本次作业的目标是
从同一方向到达的 BAT 在已经到达十字路口的第一个 BAT 后面排队;
从右边到达的 BAT 总是有先行权(除非等待的 BAT 收到要走的信号);
必须防止死锁
必须防止饥饿
一旦你 运行 代码,你会看到最后两行有 'NULL' BAT 到达的方向。需要帮助解决该问题
谢谢!
dir
是一个字符指针。所以你不能直接使用像if( dir == "North")
这样的等号你需要的是if ((strcmp(dir,"North")== 0)
在下面的循环中,
while( argv[1][i] == 'n' || argv[1][i] == 'e' ||
argv[1][i] == 's' || argv[1][i] == 'w' )
{
i++;
if(argv[1][i] == 'n'){n++;}
if(argv[1][i] == 's'){s++;}
if(argv[1][i] == 'e'){e++;}
if(argv[1][i] == 'w'){w++;}
}
您首先在循环内递增 i
。因此,对于数组 argv[1][i]
中的最后一个元素,您正在读取垃圾值。 i
的增量应该是循环中的最后一条语句。即在 if(argv[1][i] == 'w'){w++;}
之后
你的程序有未定义的行为,因为你将指向局部变量的指针传递给你的线程函数。在 bats
函数中,当取消引用指针时,您可能会得到垃圾值:
for(int j = 0; j < i; j++)
{
pthread_create(&tid[j], NULL, bats, (void*) &j);
}
j
在 for 循环中是局部的。
您可以分配内存来保存 int 的值
变量:
for(int j = 0; j < i; j++)
{
int* var = malloc(sizeof(int));
*var = j;
pthread_create(&tid[j], NULL, bats, var);
}
记得在bats
函数中释放这个内存:
void *bats(void *arg)
{
int index = *(int *)arg;
//...
leave(index, dir);
free (arg); // <--
pthread_exit(NULL); // instead of _exit(0);
}
嘿,我在解决导致一些不需要的 NULL 显示在我的最终输出中的错误时遇到了问题。当您 运行 程序在 运行ning 之前在命令行中输入一个字符串,例如 'nnseeeewwwew'。
这是代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
/* mutex */
pthread_mutex_t thisMutex;
/* Condition Variables */
sem_t nQueue, eQueue, sQueue, wQueue;
int nFirst, sFirst, eFirst, wFirst;
int done = 0;
/* Thread Prototypes */
void *bats(void *);
void *checking(void *);
/* Prototypes */
void arrive(int num, char *dir);
void cross();
void leave(int num, char *dir);
void check();
/* Global pointer to argv */
char *directions = NULL;
int main(int argc, char *argv[])
{
int i = 0,
n = 0,
s = 0,
e = 0,
w = 0;
directions = argv[1];
while( argv[1][i] == 'n' || argv[1][i] == 'e' ||
argv[1][i] == 's' || argv[1][i] == 'w' )
{
if(argv[1][i] == 'n'){n++;}
if(argv[1][i] == 's'){s++;}
if(argv[1][i] == 'e'){e++;}
if(argv[1][i] == 'w'){w++;}
i++;
}
pthread_mutex_init(&thisMutex, NULL);
sem_init(&nQueue, 0, n);
sem_init(&sQueue, 0, s);
sem_init(&eQueue, 0, e);
sem_init(&wQueue, 0, w);
nFirst = sFirst = eFirst = wFirst = 0;
pthread_t tid[i];
pthread_t checker;
pthread_create(&checker, NULL, checking, NULL);
for(int j = 0; j < i; j++)
{ pthread_create(&tid[j], NULL, bats, (void*) &j); }
for(int j = 0; j < i; j++)
{ pthread_join(tid[j], NULL); }
done = 1;
pthread_join(checker, NULL);
pthread_mutex_destroy(&thisMutex);
sem_destroy(&nQueue);
sem_destroy(&sQueue);
sem_destroy(&wQueue);
sem_destroy(&eQueue);
return 0;
}
void *checking(void *arg)
{
while( done == 0 )
{
if( nFirst == 1 || sFirst == 1 ||
eFirst == 1 || wFirst == 1 )
check();
}
exit(0);
}
void *bats(void *arg)
{
int index = *(int *)arg;
char *dir;
switch (directions[index])
{
case 'n':
dir = "North";
break;
case 's':
dir = "South";
break;
case 'e':
dir = "East";
break;
case'w':
dir = "West";
break;
}
arrive(index, dir);
leave(index, dir);
_exit(0);
}
/* Functions */
void arrive(int num, char *dir)
{
printf("BAT %d from %s arrives at crossing\n", num, dir);
if(strcmp(dir,"North")== 0)
{
sem_wait(&nQueue);
nFirst = 1;
while(eFirst == 1){ /* do nothing */ }
cross();
nFirst = 0;
sem_post(&nQueue);
}
else if(strcmp(dir,"West")== 0)
{
sem_wait(&wQueue);
wFirst = 1;
while(nFirst == 1){ /* do nothing */ }
cross();
wFirst = 0;
sem_post(&wQueue);
}
else if(strcmp(dir,"South")== 0)
{
sem_wait(&sQueue);
sFirst = 1;
while(wFirst == 1){ /* do nothing */ }
cross();
sFirst = 0;
sem_post(&sQueue);
}
else if(strcmp(dir,"East")== 0)
{
sem_wait(&eQueue);
eFirst = 1;
while(sFirst == 1){ /* do nothing */ }
cross();
eFirst= 0;
sem_post(&eQueue);
}
}
void cross()
{
pthread_mutex_lock(&thisMutex);
sleep(1);
pthread_mutex_unlock(&thisMutex);;
}
void leave(int num, char *dir)
{
printf("BAT %d from %s leaving crossing\n", num, dir);
}
void check()
{
if( nFirst == 1 && sFirst == 1 &&
eFirst == 1 && wFirst == 1 )
{
eFirst = 0;
sleep(1);
eFirst = 1;
}
}
本次作业的目标是
从同一方向到达的 BAT 在已经到达十字路口的第一个 BAT 后面排队;
从右边到达的 BAT 总是有先行权(除非等待的 BAT 收到要走的信号);
必须防止死锁
必须防止饥饿
一旦你 运行 代码,你会看到最后两行有 'NULL' BAT 到达的方向。需要帮助解决该问题
谢谢!
dir
是一个字符指针。所以你不能直接使用像if( dir == "North")
这样的等号你需要的是if ((strcmp(dir,"North")== 0)
在下面的循环中,
while( argv[1][i] == 'n' || argv[1][i] == 'e' || argv[1][i] == 's' || argv[1][i] == 'w' ) { i++; if(argv[1][i] == 'n'){n++;} if(argv[1][i] == 's'){s++;} if(argv[1][i] == 'e'){e++;} if(argv[1][i] == 'w'){w++;} }
您首先在循环内递增 i
。因此,对于数组 argv[1][i]
中的最后一个元素,您正在读取垃圾值。 i
的增量应该是循环中的最后一条语句。即在 if(argv[1][i] == 'w'){w++;}
你的程序有未定义的行为,因为你将指向局部变量的指针传递给你的线程函数。在 bats
函数中,当取消引用指针时,您可能会得到垃圾值:
for(int j = 0; j < i; j++)
{
pthread_create(&tid[j], NULL, bats, (void*) &j);
}
j
在 for 循环中是局部的。
您可以分配内存来保存 int 的值 变量:
for(int j = 0; j < i; j++)
{
int* var = malloc(sizeof(int));
*var = j;
pthread_create(&tid[j], NULL, bats, var);
}
记得在bats
函数中释放这个内存:
void *bats(void *arg)
{
int index = *(int *)arg;
//...
leave(index, dir);
free (arg); // <--
pthread_exit(NULL); // instead of _exit(0);
}