我正在学习创建线程以及它们如何相互交互,所以我想创建一个简单的消息队列。
我关注的模型是这样的:
现在我有点陷入我面临的问题。两个线程都想打印一些东西,但是它们彼此重叠。我的想法是,也许向客户端线程添加睡眠可以使其工作,并且成功了。
我现在的问题是,我的方法是一个好的解决方案吗?还有其他方法可以解决这个问题吗?此外,任何有关代码或改进的反馈将不胜感激。
代码:
#define MAX_SIZE 1024
#define QUEUE_NAME "/MQ"
#define MSG_STOP "END"
void *server() {
mqd_t mq;
struct mq_attr attr;
char buffer[MAX_SIZE + 1];
int state = 1;
attr.mq_flags = 0;
attr.mq_maxmsg = 100;
attr.mq_msgsize = MAX_SIZE;
attr.mq_curmsgs = 0;
mq = mq_open(QUEUE_NAME, O_CREAT | O_RDONLY, 0644, &attr);
while (state) {
mq_receive(mq, buffer, MAX_SIZE, NULL);
if (!strncmp(buffer, MSG_STOP, strlen(MSG_STOP))) {
state = 0;
printf("chat closing\n");
} else {
printf("Msg reached: %s\n", buffer);
}
}
return NULL;
}
void *client() {
mqd_t mq;
char buffer[MAX_SIZE];
mq = mq_open(QUEUE_NAME, O_WRONLY);
int state = 1;
printf("To exit the chat type END \n");
while (state) {
printf("chatting: ");
fflush(stdout);
memset(buffer, 0, MAX_SIZE);
fgets(buffer, MAX_SIZE, stdin);
if (!strncmp(buffer, MSG_STOP, strlen(MSG_STOP))) {
mq_send(mq, buffer, MAX_SIZE, 0);
state = 0;
} else {
mq_send(mq, buffer, MAX_SIZE, 0);
printf("Msg sent: %s\n", buffer);
sleep(0.9);
}
}
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t1, t2;
pthread_create(&t1, NULL, &server, NULL);
pthread_create(&t2, NULL, &client, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
未添加睡眠的结果:
To exit the chat type END
chatting: test
Msg sent: test
chatting: Msg reached: test
test2
Msg sent: test2
chatting: Msg reached: test2
END
chat closing
添加睡眠后:
To exit the chat type END
chatting: test
Msg sent: test
Msg reached: test
chatting: test2
Msg sent: test2
Msg reached: test2
chatting: END
chat closing
我的想法是也许向客户端线程添加睡眠可以使其工作。
有时添加
sleep
调用将使多线程程序按照您期望的方式工作,但在大多数编程语言/库/操作系统中,sleep
永远无法保证 使任何工作正常工作。
别被愚弄了。如果您的程序有一个与线程相关的错误,并且
sleep
似乎 修复了它,那么可能它真正所做的只是使错误更难以重现。也许你已经使它很难重现,为了你的目的,它可能根本不再存在了。但只要尝试将该代码发送给客户,然后然后看看会发生什么。
当金钱或您的声誉受到威胁时,不要依赖
sleep
来协调线程的行为。
还有其他方法可以解决这个问题吗?
任何时候你想确保两个线程在尝试使用某些共享资源时不会互相干扰(例如,本例中的
stdout
),你首先应该想到的是使用互斥体。
互斥体可以处于两种状态之一,我将其称为“锁定”和“可用”。 (有时它们有其他名称。)它有两个有用的属性:
不允许两个线程同时锁定互斥锁。如果一个线程在另一个线程已经已经锁定它时尝试锁定它,那么第一个线程将被迫等待,直到另一个线程释放互斥锁。
一个线程在锁定互斥体时对共享变量所做的更改保证在第二个线程随后锁定同一互斥体后对任何其他线程都可见。有些人称之为“同步”,互斥锁是实现它的一种方法。如果两个线程在没有任何同步的情况下访问相同的变量,那么就会产生难以重现的错误,有时甚至很难找到。