我这里有一个程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <errno.h>
#include "linkedlist.h"
#include "globals.h"
#include "card.h"
#include "logging.h"
#include "stack.h"
#include "servers.h"
#include "player.h"
#define VERSION "0.1"
#define ERR -1
/*
* Main function runs, loads 5 named table objects. For each table
* created a fork is created for that specific table object that
* allows each table to run independently.
*
* Usernames details are also created and prepared. These are hardcoded
* until I add database logic later.
*
* After the tables are prepared, the main function starts a server
* listening thread that waits for UNIX sockets to connect to it. When
* they arrive it spawns a handling thread that does a quick login check
* and then asks the user which of the named tables they want to play on
*
* The socket information is then connected to the table, so the table can
* then communicate with user. When the table is full, the table algorithm
* is responcible for basically looping contineously, creating new "games"
* until only one player is left. He is the winner. When he wins, the table
* exits.
*
* the game loop does all the real work for the texas holdem game, hosting
* rounds of bets, dealing cards etc.
*/
void table_process(int tables_id);
void main_game_loop(void);
int main(int argc, char **argv)
{
int main_process_id;
int connection_process_id;
char table_config_name[8];
char *table_name;
stack *my_deck;
card *current_card;
int i;
int s;
printf("------------ PRT POKER -----------\nA texas holdem poker server\n~~~~Version: %s~~~~~~~\n", VERSION);
config_load("poker.conf");
logging_init();
if (key = ftok("/mnt/mydocuments/git/texas_holdem/poker", 'a') == -1)
{
logging_critical("Call to ftok failed");
exit(1);
}
// if ((msg_queue = msgget(key, 0644 | IPC_CREAT)) == -1)
// {
// logging_critical("call to msgget failed");
// exit(1);
// }
//read int the list of tables from the configuration file
config_get_int("players_per_table", &player_count);
logging_info("players per table: %i", *player_count);
config_get_int("table_count", &table_count);
logging_info("number of tables: %i", *table_count);
table_names = malloc(sizeof(char*) * (*table_count));
logging_info("Table count: %d", *table_count);
for (i = 0; i < *table_count; i++)
{
sprintf(table_config_name, "table_%d", (i + 1));
config_get_string(table_config_name, &table_name);
table_names[i] = table_name;
logging_info("Created table %d: %s", i, table_name);
if (fork() == 0)
{
table_process(i);
_exit(0);
}
}
main_process_id = getpid();
connection_process_id = fork();
logging_info("connecton process: %d", connection_process_id);
if (connection_process_id == 0)
{
wait_for_players();
_exit(0);
}
else
waitpid(connection_process_id, &s, 0);
logging_info("Application ended");
return 0;
}
void table_process(int table_id)
{
linkedlist *players;
player *p;
int players_added;
if ((msg_queue = msgget(key, 0644 | IPC_CREAT)) == -1)
{
logging_critical("call to msgget failed");
exit(1);
}
logging_info("table %s (%i) running in process %d", table_names[table_id], table_id, getpid());
players = linkedlist_new();
players_added = *player_count;
while (players_added > 0)
{
logging_info("still waiting for %i players to join %s with queue id %i", players_added, table_names[table_id], table_id + MSG_QUEUE_OFFSET);
//THIS DOESN'T WORK!!!! IT DOESN'T WAKE UP
if (msgrcv(msg_queue, &p, sizeof(player), table_id + MSG_QUEUE_OFFSET, 0) == -1)
{
logging_critical("recieving from message queue failed");
_exit(1);
}
else
logging_info("played joined %s", table_names[table_id]);
logging_debug("player = %s, %s", p->name, p->password);
players_added--;
}
logging_info("table %s ready to start!!!!!", table_names[table_id]);
}
void main_game_loop(void)
{
logging_debug("main_game_loop");
}
程序应该启动并分成4个线程。前三个线程调用msgget()来创建系统V消息队列。
然后他们都调用msgrcv()并等待不同的id发生。
第四个线程侦听连接客户端,然后调用msgsnd()。出于某种原因,没有一个等待消息的分叉再次醒来。
我确定消息队列是正确的。
我在msgsrcv之前有一个print语句,所以我可以看到fork发生了正确的每个语句。之后还有一个打印声明,所以我可以看到代码没有通过它。
我从命令提示符运行了ipcs。
肯定会创建一个消息队列,并且其中有一条消息。
如果我将msgrcv更改为“0”,那么其中一个线程将被唤醒,但这不是我想要的行为。
msgget()不会抛出错误。
msgsnd()没有抛出错误。
我很肯定结构中的id是正确的。
任何想法我做错了什么?
答案 0 :(得分:2)
至少有一件事是错的:你已经将“p”声明为指向玩家的指针,并且在将其传递给msgrcv时再次获取其地址。更重要的是,你传递的指针大小可能太大(即sizeof(播放器)&gt; sizeof(播放器*))。堆栈腐败等待发生。
然后,尝试使用strace(在Linux上;在Solaris上使用truss)来实时查看正在发生的事情。