我的线程问题很长一段时间了。当主线程将其打印出来时,此代码应该有一个工作线程增加共享整数的值。但是,我没有得到我预期的输出。
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
pthread_mutex_t lock;
int shared_data = 0; //shared data
// Often shared data is more complex than just an int.
void* thread_function(void* arg)
{
int i;
for (i = 0; i < 10; ++i)
{
// Access the shared data here.
pthread_mutex_lock(&lock);
shared_data++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(void)
{
pthread_t thread;
int i;
void* exit_status;
// Initialize the mutex before trying to use it.
pthread_mutex_init(&lock, NULL);
pthread_create(&thread, NULL, thread_function, NULL);
// Try to use the shared data.
for (i = 0; i < 10; ++i)
{
sleep(1);
pthread_mutex_lock(&lock);
printf ("\r for i= %d Shared integer 's value = %d\n", i, shared_data);
pthread_mutex_unlock(&lock);
}
printf("\n");
pthread_join(thread, &exit_status);
// Clean up the mutex when we are finished with it.
pthread_mutex_destroy(&lock);
return 0;
}
这是我的期望:
for i=0 Shared Integer 's value = 0
for i=1 Shared Integer 's value = 1
for i=3 Shared Integer 's value = 2
...
for i=10 Shared Integer 's value =10
但结果是:
for i=0 Shared Integer 's value = 0
for i=1 Shared Integer 's value = 10
for i=3 Shared Integer 's value = 10
...
for i=10 Shared Integer 's value =10
那我怎么能解决这个问题?
答案 0 :(得分:2)
主线程和工作线程同时运行。也就是说,如果没有额外的同步,那些完美匹配的循环几乎是不可能的。
您的输出正是您所期望的。生成线程所花费的时间允许主线程在另一个线程更改共享数据之前进行打印。然后,打印需要很长时间才能使另一个线程完成其循环,并在主线程进入第二次迭代之前将共享数据增加到10。
在一个完美的世界中,这个使用条件变量的小黑客会得到你想要的东西:
编辑:条件变量是一个坏主意。这是使用伪原子变量的工作版本,不包含UB的 :
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
pthread_mutex_t want_incr_mut;
pthread_mutex_t done_incr_mut;
int want_incr = 0;
int done_incr = 0;
int shared_data = 0; //shared data
// Not using atomics, so...
void wait_for_want_increment()
{
while (1)
{
pthread_mutex_lock(&want_incr_mut);
if (want_incr)
{
pthread_mutex_unlock(&want_incr_mut);
return;
}
pthread_mutex_unlock(&want_incr_mut);
}
}
void wait_for_done_incrementing()
{
while (1)
{
pthread_mutex_lock(&done_incr_mut);
if (done_incr)
{
pthread_mutex_unlock(&done_incr_mut);
return;
}
pthread_mutex_unlock(&done_incr_mut);
}
}
void done_incrementing()
{
pthread_mutex_lock(&done_incr_mut);
done_incr = 1;
pthread_mutex_lock(&want_incr_mut);
want_incr = 0;
pthread_mutex_unlock(&want_incr_mut);
pthread_mutex_unlock(&done_incr_mut);
}
void want_increment()
{
pthread_mutex_lock(&want_incr_mut);
want_incr = 1;
pthread_mutex_lock(&done_incr_mut);
done_incr = 0;
pthread_mutex_unlock(&done_incr_mut);
pthread_mutex_unlock(&want_incr_mut);
}
// Often shared data is more complex than just an int.
void* thread_function(void* arg)
{
int i;
for (i = 0; i < 10; ++i)
{
wait_for_want_increment();
// Access the shared data here.
shared_data++;
done_incrementing();
}
return NULL;
}
int main(void)
{
pthread_t thread;
int i;
void* exit_status;
// Initialize the mutex before trying to use it.
pthread_mutex_init(&want_incr_mut, NULL);
pthread_mutex_init(&done_incr_mut, NULL);
pthread_create(&thread, NULL, thread_function, NULL);
// Try to use the shared data.
for (i = 0; i <= 10; ++i)
{
printf("\r for i= %d Shared integer 's value = %d\n", i, shared_data);
if (i == 10) break;
want_increment();
wait_for_done_incrementing();
}
printf("\n");
pthread_join(thread, &exit_status);
// Clean up the mutexes when we are finished with them.
pthread_mutex_destroy(&want_incr_mut);
pthread_mutex_destroy(&done_incr_mut);
return 0;
}
在这里,我们告诉工人我们想要一个增量并等待他说我们在继续之前完成了。与此同时,工人等待我们想要增加并告诉我们何时完成。
我还将主循环更改为十,因为这是我认为你想要的。
这是我的输出:
for i= 0 Shared integer 's value = 0
for i= 1 Shared integer 's value = 1
for i= 2 Shared integer 's value = 2
for i= 3 Shared integer 's value = 3
for i= 4 Shared integer 's value = 4
for i= 5 Shared integer 's value = 5
for i= 6 Shared integer 's value = 6
for i= 7 Shared integer 's value = 7
for i= 8 Shared integer 's value = 8
for i= 9 Shared integer 's value = 9
for i= 10 Shared integer 's value = 10