我有功能display.c:
/* DO NOT EDIT THIS FILE!!! */
#include <stdio.h>
#include <unistd.h>
#include "display.h"
void display(char *str)
{
char *p;
for (p=str; *p; p++)
{
write(1, p, 1);
usleep(100);
}
}
而display.h是:
/* DO NOT EDIT THIS FILE!!! */
#ifndef __CEID_OS_DISPLAY_H__
#define __CEID_OS_DISPLAY_H__
void display(char *);
#endif
我的任务是使用pthreads以获得以下输出:
abcd
abcd
abcd
..
..
请注意,我不能编辑文件display.c或文件display.c。我必须使用互斥锁才能成功显示上面显示的输出。
下面的代码块是我最终达到我想要的结果的最接近的尝试:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
#include "display.h"
pthread_t mythread1;
pthread_t mythread2;
pthread_mutex_t m1, m2;
void *ab(void *arg)
{
pthread_mutex_lock(&m1);
display("ab");
pthread_mutex_unlock(&m1);
}
void *cd(void *arg)
{
pthread_mutex_lock(&m1);
display("cd\n");
pthread_mutex_unlock(&m1);
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&m1, NULL);
pthread_mutex_init(&m2, NULL);
int i;
for(i=0;i<10;i++)
{
pthread_create(&mythread1, NULL, ab, NULL);
pthread_create(&mythread2, NULL, cd, NULL);
}
pthread_join(mythread1, NULL);
pthread_join(mythread2, NULL);
pthread_mutex_destroy(&m1);
pthread_mutex_destroy(&m2);
return EXIT_SUCCESS;
}
上面代码的输出是这样的:
abcd
abcd
abcd
abcd
ababcd
cd
abcd
abcd
abcd
abcd
如您所见,“ ab”和“ cd \ n”从不混合,但是每次我运行代码时,输出都会不同。我想确保每次运行此代码时输出为:
abcd
abcd
abcd
十次。
因为我无法从已经知道的事情中找到任何解决方案,所以我真的很坚持。
最佳答案
互斥锁本身无法解决您的问题。它可以防止两个线程同时运行,但是不能强制它们轮流运行。
您可以使用互斥锁之外的条件变量或一对信号量来执行此操作。不管哪种方式,关键是要始终保持对线程转向的感觉。
我自己,我认为信号量方法更易于理解和编码。每个信号量主要与一个不同的线程关联。该线程必须锁定信号量才能继续。完成一次迭代后,它将解锁另一个信号量以允许另一个线程继续运行,然后循环返回以尝试再次锁定其自己的信号量(尚无法执行此操作)。另一个线程的工作方式相同,但是信号灯角色相反。大概是:
sem_t sem1;
sem_t sem2;
// ...
void *thread1_do(void *arg) {
int result;
do {
result = sem_wait(&sem1);
// do something
result = sem_post(&sem2);
} while (!done);
}
void *thread2_do(void *arg) {
int result;
do {
result = sem_wait(&sem2);
// do something else
result = sem_post(&sem1);
} while (!done);
}
为了简洁起见,省略了信号量初始化,错误检查等。
更新后添加:
由于您现在添加了必须使用互斥锁(大概以非平凡的方式),因此下一个最佳方法是引入条件变量(与互斥锁一起使用)和普通的共享变量以跟踪哪个线程打开了它是。然后,每个线程都在等待条件变量以获取互斥量,在互斥量的保护下,该共享变量将检查共享变量以查看是否轮到它了,如果是,则继续。大概是:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int whose_turn = 1;
// ...
void *thread1_do(void *arg) {
int result;
result = pthread_mutex_lock(&mutex);
while (1) {
if (whose_turn == 1) {
// do something
whose_turn = 2; // it is thread 2's turn next
}
// break from the loop if finished
result = pthread_cond_broadcast(&cond);
result = pthread_cond_wait(&cond, &mutex);
}
result = pthread_mutex_unlock(&mutex);
}
void *thread1_do(void *arg) {
int result;
result = pthread_mutex_lock(&mutex);
while (1) {
if (whose_turn == 2) {
// do something else
whose_turn = 1; // it is thread 1's turn next
}
// break from the loop if finished
result = pthread_cond_broadcast(&cond);
result = pthread_cond_wait(&cond, &mutex);
}
result = pthread_mutex_unlock(&mutex);
}
为简便起见,再次省略了错误检查。
特别要注意的是,当线程等待条件变量时,它会释放关联的互斥量。从等待返回之前,它需要互斥量。还要注意,每个在每次迭代时检查是否轮到它继续进行。这是必需的,因为可能会因等待条件变量而导致虚假唤醒。
关于c - 内存同步,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34684874/