#include "cs241.c"
#define THREAD_COUNT 10
int list_s;
int connections[THREAD_COUNT];
char space[THREAD_COUNT];
int done = 0;
pthread_mutex_t muxlock = PTHREAD_MUTEX_INITIALIZER;
int *numbers;
int numbers_count;
void *listener(void *arg) {
int n = *(int *) arg;
FILE *f = fdopen(connections[n], "r");
if (f == NULL)
printf("Could not open file\n");
char *line = NULL;
size_t *len = malloc(sizeof(int));
while(getline(&line, len, f) != -1) {
printf("%s", line);
if (strcmp("END", line) == 0) {
pthread_mutex_lock(&muxlock);
done = 1;
pthread_mutex_unlock(&muxlock);
}
}
space[n] = 't';
fclose(f);
free(len);
close(connections[n]);
return NULL;
}
void initialize() {
int n;
for (n = 0; n < THREAD_COUNT; n++) {
space[n] = 't';
}
}
int check() {
int index;
for (index = 0; index < THREAD_COUNT; index++) {
if (space[index] == 't') {
space[index] = 'f';
return index;
}
}
return 0;
}
int main(int argc, char *argv[]) {
int port = 0;
int binder;
int lis;
int i = 0;
int *j = malloc(sizeof(int));
initialize();
pthread_t threads[THREAD_COUNT];
if ((argc != 2) || (sscanf(argv[1], "%d", &port) != 1)) {
fprintf(stderr, "Usage: %s [PORT]\n", argv[0]);
exit(1);
}
if (port < 1024) {
fprintf(stderr, "Port must be greater than 1024\n");
exit(1);
}
// set the initial conditions for the numbers array.
numbers = malloc(sizeof(int));
numbers_count = 0;
struct sockaddr_in servaddr; // socket address structure
// set all bytes in socket address structure to zero, and fill in the relevant data members
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
list_s = socket(AF_INET, SOCK_STREAM, 0);
if (list_s < 0) {
printf("Could not create socket\n");
exit(EXIT_FAILURE);
}
binder = bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (binder < 0) {
printf("Could not bind socket\n");
exit(EXIT_FAILURE);
}
lis = listen(list_s, SOMAXCONN);
if (lis < 0) {
printf("Could not listen on socket\n");
exit(EXIT_FAILURE);
}
SET_NON_BLOCKING(list_s);
while (done != 1) {
connections[i] = accept(list_s, NULL, NULL);
if (connections[i] < 0) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
continue;
printf("Could not accept connection\n");
exit(EXIT_FAILURE);
}
i = check();
*j = i;
SET_BLOCKING(list_s);
pthread_create(&threads[i], NULL, listener, j);
}
// Verify the array.
//verify(numbers, numbers_count);
free(j);
close(list_s);
exit(EXIT_SUCCESS);
}
所以我在main()中有一个while循环,当'done'= 1时它应该退出。这是由listener()设置的,当它收到'END'时。第一个问题是,当我在第一次迭代时发送'END'时,while循环不会退出,只有在发送了另一个'END'之后。
我在另一个文件中有两个宏SET_NON_BLOCKING和SET_BLOCKING用于解锁和阻塞套接字,因此如果没有,它会等待连接。下一个问题是当我不使用这些宏时,listener()中的getline()无法读取从流中输出的所有内容。当我使用它们时,它根本无法打开流。
我认为一些问题在于将'j'传递给线程,因为当第二个线程启动时,它会在第一个线程可以读取之前覆盖'j'。然而,我已经在这里呆了几天,无法到达任何地方。任何帮助将不胜感激。谢谢!
另外我想问一下我的套接字阻塞和线程锁定是否在正确的位置?
答案 0 :(得分:1)
你可能必须发送两次END,因为你的主线程在产生监听器线程后立即阻塞accept()
。由于其在accept()
上被屏蔽,因此无法看到done == 1
。
您可以通过保持非阻止模式来解决此问题。如果你这样做,你可能想睡觉以避免在紧密的循环中旋转。另一种方法是发送一个信号唤醒接受,使其设置EINTR。
在将连接索引传递给侦听器线程方面,您可能正确地在线程之间覆盖了值。由于int
将需要与void *
相同或更少的字节,因此您实际上可以直接传递int
。例如:
pthread_create(&threads[i], NULL, listener, (void *)i);
然后在听众中:
int n = (int)arg;
这是一种黑客行为。更完整的解决方案是使用malloc为每个线程分配单独的参数结构。然后,侦听器线程将负责释放参数。
struct params *p = malloc(sizeof(struct params));
p.index = i;
pthread_create(&threads[i], NULL, listener, p);
然后在听众中:
struct params *p = args;
if (p == NULL) {
// handle error
return NULL;
}
int n = p->index;
free(p);
答案 1 :(得分:1)
您管理connections[]
和space[]
数组的方式似乎有很多问题:
connections[i]
的连接,但传递给i
主题的listener
是由check()
返回的主题 - 这可能是完全不同的i
j
1}}。listener
只被分配一次,并且相同的分配用于每个线程创建。如果两个或多个线程几乎同时启动,那么你将失去应该传递给其中一些线程的索引。space[n] = 't';
标记连接可用(我假设这是connections[n]
的意图),但随后使用len
关闭连接。这些都不是通过任何同步执行的。其他一些评论:
done
?main()
while
循环中getline()
的检查应受互斥锁保护getline()
我假设它是一组以换行符终止的行。在这种情况下,请记住来自"END"
文档的一些信息:“缓冲区以空值终止,并包含换行符,如果找到了”。如果strcmp("END",line)
行包含换行符,0
将不会返回{{1}}。