在 C 中使用线程时的奇怪行为
Strange behavior when using threads in C
我对线程还很陌生,很难理解下面代码的行为。假设我使用命令行输入 10,我希望输出为 20,因为有两个线程分别将 count 的值递增 10 次。但是,每次我 运行 这个程序时,输出都不是 20。以下是我的一些尝试:
命令行输入:10,预期输出:20,实际输出:15
命令行输入:10,预期输出:20,实际输出:10
命令行输入:10,预期输出:20,实际输出:13
命令行输入:10,异常输出:20,实际输出:20
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
/* Increment global count */
for(i = 0; i < iterations; i++) {
count++;
}
pthread_exit(NULL);
}
你的增量不是原子的,你没有插入任何同步机制,所以你的一个线程当然会覆盖 count
而另一个仍在递增它,导致 "losses"增量。
您需要一个原子增量函数(在 Windows 上,您有 InterlockedIncrement
为此),或一个显式锁定机制(如互斥锁)。
在汇编中对两个数求和通常需要几条指令:
- 将数据移动到某个寄存器
- 向该寄存器添加一些值
- 将数据从寄存器移动到内存中的某个单元格
因此,当操作系统为您的程序提供系统时间时,它并不能保证所有这些操作都在没有任何中断的情况下完成。这些被称为临界区。每次进入这样的部分,都需要同步两个线程。
这应该有效:
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
pthread_mutex_t lock;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
pthread_mutex_init(&lock); //initialize the mutex
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_mutex_destroy(&lock); //destroy the mutex, its similar to malloc and free
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
int local_count = 0;
/* Increment global count */
for(i = 0; i < iterations; i++) {
local_count++;
}
pthread_mutex_lock(&lock); //enter a critical section
count += local_count;
pthread_mutex_unlock(&lock); //exit a critical section
pthread_exit(NULL);
}
我对线程还很陌生,很难理解下面代码的行为。假设我使用命令行输入 10,我希望输出为 20,因为有两个线程分别将 count 的值递增 10 次。但是,每次我 运行 这个程序时,输出都不是 20。以下是我的一些尝试:
命令行输入:10,预期输出:20,实际输出:15
命令行输入:10,预期输出:20,实际输出:10
命令行输入:10,预期输出:20,实际输出:13
命令行输入:10,异常输出:20,实际输出:20
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
/* Increment global count */
for(i = 0; i < iterations; i++) {
count++;
}
pthread_exit(NULL);
}
你的增量不是原子的,你没有插入任何同步机制,所以你的一个线程当然会覆盖 count
而另一个仍在递增它,导致 "losses"增量。
您需要一个原子增量函数(在 Windows 上,您有 InterlockedIncrement
为此),或一个显式锁定机制(如互斥锁)。
在汇编中对两个数求和通常需要几条指令:
- 将数据移动到某个寄存器
- 向该寄存器添加一些值
- 将数据从寄存器移动到内存中的某个单元格
因此,当操作系统为您的程序提供系统时间时,它并不能保证所有这些操作都在没有任何中断的情况下完成。这些被称为临界区。每次进入这样的部分,都需要同步两个线程。
这应该有效:
#include <stdio.h>
#include <pthread.h>
/* The threads will increment this count
* n times (command line input).
*/
int count = 0;
pthread_mutex_t lock;
/* The function the threads will perform */
void *increment(void *params);
int main(int argc, char *argv[]) {
/* Take in command line input for number of iterations */
long iterations = (long)atoi(argv[1]);
pthread_t thread_1, thread_2;
pthread_mutex_init(&lock); //initialize the mutex
/* Create two threads. */
pthread_create(&thread_1, NULL, increment, (void*)iterations);
pthread_create(&thread_2, NULL, increment, (void*)iterations);
/* Wait for both to finish */
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
/* Print the final result for count. */
printf("Count = %d.\n", count);
pthread_mutex_destroy(&lock); //destroy the mutex, its similar to malloc and free
pthread_exit(NULL);
}
void *increment(void *params) {
long iterations = (long)params;
int i;
int local_count = 0;
/* Increment global count */
for(i = 0; i < iterations; i++) {
local_count++;
}
pthread_mutex_lock(&lock); //enter a critical section
count += local_count;
pthread_mutex_unlock(&lock); //exit a critical section
pthread_exit(NULL);
}