【问题标题】:Multithreading with Windows API in CC 中的 Windows API 多线程
【发布时间】:2021-02-06 21:01:23
【问题描述】:

我已经编写了如下代码,据说它应该以随机顺序打印出从 0 到 10 的数字。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define THREAD_COUNT 10

DWORD WINAPI t_work(LPVOID param) {
    printf("%d\n", *((int *) param));
    return 0;
}

int main() {

    DWORD *thread_id = malloc(THREAD_COUNT * sizeof(DWORD));
    HANDLE *threads = malloc(THREAD_COUNT * sizeof(HANDLE));
    int *data = malloc(THREAD_COUNT * sizeof(int));
    int i;
    for (i = 0; i < THREAD_COUNT; i++) {
        *(data + i) = i;
        //printf("Debugging value: %d\n", i);
        *(threads + i) = CreateThread(
            NULL,               // default security attributes
            0,                  // use default stack size
            t_work,             // thread function name
            (data + i),         // argument to thread function
            0,                  // use default creation flags
            (thread_id + i));   // returns the thread identifier
    }
    WaitForMultipleObjects(THREAD_COUNT, threads, TRUE, INFINITE);
    int k;
    for (k = 0; k < THREAD_COUNT; k++) {
        CloseHandle(*(threads + k));
    }

    // free memory
    free(thread_id);
    free(data);

    return 0;
}

问题是,无论出于何种原因,打印输出总是不正确的。总是有一些随机数丢失和一些重复。以下是程序的一些运行结果:

运行 #1

PS C:\Users\tdw\Work\C Test Project> .\hw.exe
0
8
9
9
9
1
3
5
4
2

运行 #2

PS C:\Users\tdw\Work\C Test Project> .\hw.exe
0
6
6
8
8
9
9
4
3
3

编辑 1:

我正在使用 Visual Studio Code 版本 1.50.1

这里是编译器的细节:

PS C:\Users\tdw\Work\C Test Project> gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/10/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: /mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0/configure - 
-srcdir=/mnt/share/cygpkgs/gcc/gcc.x86_64/src/gcc-10.2.0 --prefix=/usr -- 
exec- 
prefix=/usr --localstatedir=/var --sysconfdir=/etc -- 
docdir=/usr/share/doc/gcc 
--htmldir=/usr/share/doc/gcc/html -C --build=x86_64-pc-cygwin --host=x86_64- 
pc-cygwin --target=x86_64-pc-cygwin --without-libiconv-prefix --without- 
libintl-prefix --libexecdir=/usr/lib --with-gcc-major-version-only --enable- 
shared --enable-shared-libgcc --enable-static --enable-version-specific- 
runtime-libs --enable-bootstrap --enable-__cxa_atexit --with-dwarf2 --with- 
tune=generic --enable-languages=c,c++,fortran,lto,objc,obj-c++ --enable- 
graphite --enable-threads=posix --enable-libatomic --enable-libgomp --enable- 
libquadmath --enable-libquadmath-support --disable-libssp --enable-libada -- 
disable-symvers --with-gnu-ld --with-gnu-as --with-cloog- 
include=/usr/include/cloog-isl --without-libiconv-prefix --without-libintl- 
prefix --with-system-zlib --enable-linker-build-id --with-default-libstdcxx- 
abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.2.0 (GCC)

【问题讨论】:

  • 我不认为你的指针算法是正确的。你不想用数组来代替吗?
  • @Will 我无法重现您的错误。您的代码(有或没有return 0)在 VS-2019 中按预期运行,使用 clang-cl 或 MSVC。
  • 我仍然认为使用普通数组来推理会简单得多。
  • @Will - 打印printf("++%x&gt; %u\n", GetCurrentThreadId(), *((int *) param)); 并闭环printf("--%x&gt; %u\n", thread_id[i], data[i]);
  • 是的!我是对的,问题出在printf。我会写一个答案。

标签: c windows multithreading


【解决方案1】:

问题在于线程函数t_work,它正在调用printf。 根据您的平台,printf 不一定是可重入的。 在 Visual Studio 环境中,printf 可能受到一些互斥锁的保护,并且一切正常。 但是对于 GCC 及其 libc,该 I/O 函数中可能会发生竞争。

解决方案:使用互斥锁保护printf。 例如:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define THREAD_COUNT 10
static CRITICAL_SECTION mutex;

DWORD WINAPI t_work(LPVOID param) {
    EnterCriticalSection(&mutex);
    printf("%d\n", *((int*)param));
    LeaveCriticalSection(&mutex);
    return 0;
}

int main() {
    InitializeCriticalSection(&mutex);
    DWORD* thread_id = malloc(THREAD_COUNT * sizeof(DWORD));
    HANDLE* threads = malloc(THREAD_COUNT * sizeof(HANDLE));
...

【讨论】:

  • 这个答案是正确的!
猜你喜欢
  • 1970-01-01
  • 2014-04-02
  • 2016-06-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-11
  • 2020-07-06
  • 2015-03-17
相关资源
最近更新 更多