Thread: Multi threading examples please

  1. #1
    Registered User kingnoger's Avatar
    Join Date
    Sep 2016
    Location
    mesquite tx
    Posts
    10

    Question Multi threading examples please

    Hey I need some multi- threading example runnable console win32 application code that will give me some more resources for less lag in my game. I am working on thanks. They have to be examples with no errors. And please do know that I am using windows 10 64bit and visual studio 2013 for windows also my build is 64bit thanks. Please list the code in a file or here thanks so much.

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Link to a multi-threaded file copy program that uses a message interface for queuing and synchronization between threads. Each message contains a poitner to a buffer and a size count. One thread gets messages from the free pool, reads data into them, and enqueues them to the other thread. The other thread gets messages from its input queue, writes the data from the message, and enqueues the messages back to the free pool. Most of the multi-threaded embedded devices I've worked with use the same messaging concept.

    http://rcgldr.net/misc/mtcopy.zip

    Games often need one or more threads to run at a fixed frequency. Here is an example that avoids long term drift by basing the delays on an initial reading of a timer. It uses an accumulating remainder (uRem) to keep the frequency as accurate as possible. The example code check for 2ms of delay before doing a sleep, because Sleep(1) with Windows XP can occasionally sleep for almost 2 ms with a Sleep(1). For Windows 7 and later this was fixed. I don't know about Windows Vista.

    Code:
    /* code for a thread to run at fixed frequency */
    typedef unsigned long long UI64;        /* unsigned 64 bit int */
    #define FREQ    60                      /* frequency */
    DWORD    dwLateStep;                    /* late step count */
    LARGE_INTEGER liPerfFreq;               /* 64 bit frequency */
    LARGE_INTEGER liPerfTemp;               /* used for query */
    UI64 uFreq = FREQ;                      /* thread frequency */
    UI64 uOrig;                             /* original tick */
    UI64 uWait;                             /* tick rate / freq */
    UI64 uRem = 0;                          /* tick rate % freq */
    UI64 uPrev;                             /* previous tick based on original tick */
    UI64 uDelta;                            /* current tick - previous */
    UI64 u2ms;                              /* 2ms of ticks */
    UI64 i;
    
        /* ... */ /* wait for some event to start thread */
        QueryPerformanceFrequency(&liPerfFreq);
        u2ms = ((UI64)(liPerfFreq.QuadPart)+499) / ((UI64)500);
    
        timeBeginPeriod(1);                 /* set period to 1ms */
        Sleep(128);                         /* wait for it to stabilize */
    
        QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
        uOrig = uPrev = liPerfTemp.QuadPart;
    
        while(1){
            /* update uWait and uRem based on uRem */
            uWait = ((UI64)(liPerfFreq.QuadPart) + uRem) / uFreq;
            uRem  = ((UI64)(liPerfFreq.QuadPart) + uRem) % uFreq;
            /* wait for uWait ticks */
            while(1){
                QueryPerformanceCounter((PLARGE_INTEGER)&liPerfTemp);
                uDelta = (UI64)(liPerfTemp.QuadPart - uPrev);
                if(uDelta >= uWait)
                    break;
                if((uWait - uDelta) > u2ms)
                    Sleep(1);
            }
            if(uDelta >= (uWait*2))
                dwLateStep += 1;
            uPrev += uWait;
            /* fixed frequency code goes here */
            /*  along with some type of break when done */
        }
    
        timeEndPeriod(1);                   /* restore period */
    Last edited by rcgldr; 12-22-2016 at 10:02 PM.

  3. #3
    Old Took
    Join Date
    Nov 2016
    Location
    Londonistan
    Posts
    121
    Your code has warts. You might find this an interesting article....
    Hungarian Warthogs

  4. #4
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by Hobbit View Post
    Your code has warts. You might find this an interesting article.... Hungarian Warthogs
    Since Windows API is Hungarian, I use Hungarian for Windows programs. UI64 is there because it's old code; it should be UINT64, following the upper case standard used for Windows API types:

    Windows Data Types (Windows)

    Naming conventions haven't been an issue for me.

    As for changing variable types and then having to change names, there are scripts and or utilities that can perform a set of name changes in a single pass over an entire source tree. I've written utilities like this at some of the companies I've worked for. Tools and utilities like this seem to be common when dealing with large projects.

    I was surprised with the reference to Colossal Cave Adventure, "xyzzy".
    Last edited by rcgldr; 12-23-2016 at 02:24 AM.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,656
    If you need to ask, you're not ready to deal with thread programming.

    http://wiki.c2.com/?ThreadsConsideredHarmful

    Consider these observations.
    Brian Kernighan - Wikiquote
    Quote Originally Posted by BrianKernighan
    Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
    If debugging the hardest problems in a single threaded program rates a '10', then debugging the hardest problems in a multi-threaded program rates about '1000'.
    Heisenbug - Wikipedia
    These will regularly screw with your mind, eat you for breakfast and then spit you out.
    The first time you come across a bug which appears / disappears / moves with every attempt to debug it is a truly defining experience.

    > Multi threading examples please
    You've already started in the wrong place.
    Any successful attempt at thread programming begins with good DESIGN. You need a rock-solid program design which tells you exactly what each thread does, how they all communicate and how they co-operate with one another over shared resources.

    If you start with "I've got this code and I'm adding threads', then you're just making a rod for your back.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    In the case of Windows and Visual Studio, multi-threading debugging isn't that difficult, as breakpoints work in the same manner.

    If the OP is writing a game, my guess is that the game and physics related code (if it includes stuff like Runge Kutta method to convert accelerations into velocities and positions) will end up more complicated than the multi-threading stuff.

  7. #7
    Old Took
    Join Date
    Nov 2016
    Location
    Londonistan
    Posts
    121
    Quote Originally Posted by rcgldr View Post
    Since Windows API is Hungarian, I use Hungarian for Windows programs. UI64 is there because it's old code; it should be UINT64, following the upper case standard used for Windows API types:

    Windows Data Types (Windows)

    Naming conventions haven't been an issue for me.

    As for changing variable types and then having to change names, there are scripts and or utilities that can perform a set of name changes in a single pass over an entire source tree. I've written utilities like this at some of the companies I've worked for. Tools and utilities like this seem to be common when dealing with large projects.

    I was surprised with the reference to Colossal Cave Adventure, "xyzzy".
    Even M$ have been known to make huge errors of judgement. The internal M$ coding standard basically forbids the use of hungarian these days as it adds nothing but obfuscation overall. Yes WINAPI structure data members are decorated in this rubbish but there is no need to decorate your own code.
    Those conversation articles, there were many, were brilliant for their time, part-written by Herb Sutter who is one of the world's foremost C++ experts and at one time architect for the Visual C++ project and convener of the ISO standards committee. I remember many of them, they were always entertaining and informative and full of little references such as the one you spotted.

  8. #8
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Just learn futures and async and stuff.

  9. #9
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    I can't say I enjoy multi threading, and did appreciate that quote from Dennis Ritchie. I use multi-threading as little as possible. However, there are certainly a number of cases where it can't be avoided. When I encounter such an instance I proceed about the same way as I would through a mine field, that is, expecting instant destruction at any instant.

  10. #10
    Registered User
    Join Date
    Dec 2010
    Location
    Trinidad, CO (log cabin in middle of nowhere)
    Posts
    148
    Not sure its helpful though attacking someone's variable naming convention when all they tried to do was help another poster's request for sample code.

  11. #11
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I didn't realize the file copy program was small enough to just include here. Other than all the setup in main, each function is reasonably small. The thread 0 list (message queue) is really an "empty pool", where the empty buffers waiting to be read into are kept. Thread 0 gets each message from it's input queue, reads in a buffer and sends it to thread 1. Thread 1 gets each message from its input queue, writes the data, then returns the message back to thread 0's "empty" pool

    As mentioned before, the message queue interface shown here is how most of the multi-threaded embedded systems I've worked on operate.

    Side note - In the case of Posix / Linux, I don't think there's an native equivalent to WaitForMultipleObjects(), making it one of the few operating systems I've seen (since the 1970's) that don't include such a feature. Since the OP's question is Windows specific, this isn't an issue.

    Code:
    /*----------------------------------------------------------------------*/
    /*      mtcopy.c        multi-thread file copy demo                     */
    /*                                                                      */
    /*  Uses linked list fifo's to hold buffered data: LLIST.               */
    /*  Uses mutexes for ownership of link lists.                           */
    /*  Uses semaphores for list counts.                                    */
    /*----------------------------------------------------------------------*/
    #include <windows.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <conio.h>
    
    #define NBFR    64                      /* number of buffers */
    #define BFRSZ   0x10000                 /* buffer size */
    
    typedef struct _NODE                    /* node structure */
    {
      struct _NODE *pNext;                  /* ptr to next node */
        BYTE       *pBfr;                   /* ptr to buffer */
        DWORD       dwCnt;                  /* # bytes in buffer */
    }NODE;
    
    typedef struct _LIST                    /* linked List structure */
    {
        NODE       *pFirst;                 /* ptr to 1st  node */
        NODE       *pLast;                  /* ptr to last node */
        HANDLE      hMtxSem[2];             /* mutex and semaphore handles */
    }LIST;
    #define hMtx hMtxSem[0]                 /* mutex        == ownership */
    #define hSem hMtxSem[1]                 /* semaphore    == list count */
    
    /*----------------------------------------------------------------------*/
    /*      data                                                            */
    /*----------------------------------------------------------------------*/
    static HANDLE   htT1;                   /* thread handles */
    static LIST     llT0;                   /* thread 0 list */
    static LIST     llT1;                   /* thread 1 list */
    static NODE     aNode[NBFR];            /* array of nodes */
    static DWORD    fExitThread;            /* flag to indicate thread exit */
    static DWORD    dwThreadT1;             /* thread id's (not used) */
    static DWORD    dwExitCode;             /* exit code */
    static HANDLE   hSrc;                   /* file I/O */
    static HANDLE   hDst;
    static PBYTE    pMem;                   /* ptr to allocated memory */
    /*----------------------------------------------------------------------*/
    /*      code                                                            */
    /*----------------------------------------------------------------------*/
    static DWORD    WINAPI Thread0(LPVOID);
    static DWORD    WINAPI Thread1(LPVOID);
    static void     InitThread0List(void);
    static NODE *   GetNode(LIST *);
    static DWORD    PutNode(LIST *, NODE *);
    /*----------------------------------------------------------------------*/
    /*      main                                                            */
    /*----------------------------------------------------------------------*/
    DWORD main(DWORD argc, BYTE **argv)
    {
        hSrc    = INVALID_HANDLE_VALUE;     /* init file handles to not open */
        hDst    = INVALID_HANDLE_VALUE;
        if(argc != 3){
            printf("usage is mtcopy <src> <dst>\n");
            goto exit0;}
        pMem = malloc(BFRSZ*NBFR);          /* allocate memory */
        if(!pMem){
            _cputs("can't allocate enough memory\r\n");
            goto exit0;}
        hSrc = CreateFile(argv[1],          /* open src file */
                GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
        if(hSrc == INVALID_HANDLE_VALUE){
            printf("Can't open %s\n", argv[1]);
            goto exit0;}
        hDst = CreateFile(argv[2],          /* open dst file */
            GENERIC_ALL , 0, NULL, CREATE_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, 0);
        if(hDst == INVALID_HANDLE_VALUE){
            printf("Can't create %s\n", argv[2]);
            goto exit0;}
        /*  create mutex and semaphore for each list */
        if((llT0.hSem = CreateSemaphore(NULL,0,NBFR+1,NULL))==NULL){
            _cputs("can't create semaphore\r\n");
            goto exit0;}
        if((llT0.hMtx = CreateMutex(NULL,FALSE,NULL))==NULL){
            _cputs("can't create mutex\r\n");
            goto exit0;}
        if((llT1.hSem = CreateSemaphore(NULL,0,NBFR+1,NULL))==NULL){
            _cputs("can't create semaphore\r\n");
            goto exit0;}
        if((llT1.hMtx = CreateMutex(NULL,FALSE,NULL))==NULL){
            _cputs("can't create mutex\r\n");
            goto exit0;}
        /*  create threads */
        htT1 = CreateThread(NULL, 0, Thread1, 0, 0, &dwThreadT1);
        if(!htT1){
            _cputs("can't create thread\r\n");
            goto exit0;}
        InitThread0List();                  /* init Thread 0 list */
        Thread0((LPVOID)NULL);              /* start Thread 0 */
    exit0:
        if(htT1){                           /* close thread */
            WaitForSingleObject(htT1, INFINITE);
            CloseHandle(htT1);}
        if(llT1.hSem){                      /* close mutex, semaphore */
            CloseHandle(llT1.hSem);}
        if(llT1.hMtx){
            CloseHandle(llT1.hMtx);}
        if(llT0.hSem){
            CloseHandle(llT0.hSem);}
        if(llT0.hMtx){
            CloseHandle(llT0.hMtx);}
        if(hDst != INVALID_HANDLE_VALUE){   /* close files */
            CloseHandle(hDst);}
        if(hSrc != INVALID_HANDLE_VALUE){
            CloseHandle(hSrc);}
        if(pMem){                           /* free memory */
            free(pMem);}
        return(0);
    }
    /*----------------------------------------------------------------------*/
    /*      Thread0         read bfr from file 0                            */
    /*----------------------------------------------------------------------*/
    static DWORD WINAPI Thread0(LPVOID lpvoid)
    {
    NODE *pNode;
        while(1){
            pNode = GetNode(&llT0);         /* get node */
            ReadFile(hSrc, pNode->pBfr, BFRSZ, &(pNode->dwCnt), NULL);
            PutNode(&llT1, pNode);          /* send node to thread 1 */
            if(pNode->dwCnt == 0){          /* exit if end of file */
                return(0);}}
    }
    /*----------------------------------------------------------------------*/
    /*      Thread1         write bfr to file 1                             */
    /*----------------------------------------------------------------------*/
    static DWORD WINAPI Thread1(LPVOID lpvoid)
    {
    NODE *pNode;
    DWORD dwWrite;
    DWORD dwCnt = 1;
        while(dwCnt){
            pNode = GetNode(&llT1);         /* get node */
            dwCnt = pNode->dwCnt;           /* localize count */
            if(dwCnt)                       /* write data if count != 0 */
                WriteFile(hDst, pNode->pBfr, dwCnt, &dwWrite, NULL);
            PutNode(&llT0, pNode);}         /* return node to thread 0 */
        return(0);
    }
    /*----------------------------------------------------------------------*/
    /*      InitThread0List init thread 0 list                              */
    /*----------------------------------------------------------------------*/
    static void InitThread0List(void)
    {
    BYTE * pBfr;
    DWORD i;
        pBfr = pMem;
        for(i = 0; i < NBFR; i++){
            aNode[i].pBfr = pBfr;
            PutNode(&llT0, &aNode[i]);
            pBfr += BFRSZ;}
    }
    /*----------------------------------------------------------------------*/
    /*      GetNode     get first node from list                            */
    /*                                                                      */
    /*  WaitForMultipleObjects eliminates any thread priority issues        */
    /*----------------------------------------------------------------------*/
    static NODE * GetNode(LIST * pList)
    {
    NODE * pNode;                           /* used for return value */
    /*  wait for ownership, node, and decrement semaphore count */
        WaitForMultipleObjects(2, pList->hMtxSem, TRUE ,INFINITE);
        pNode = pList->pFirst;              /* set return value */
        pList->pFirst = pNode->pNext;       /* advance first ptr */
        if(pList->pFirst == NULL)           /* if emptied list */
            pList->pLast = NULL;            /*  reset last ptr as well */
        ReleaseMutex(pList->hMtx);          /* release ownership of list */
        return(pNode);
    }
    /*----------------------------------------------------------------------*/
    /*      PutNode     append node to end of list                          */
    /*      returns 0 if list was previously empty                          */
    /*                                                                      */
    /*  ReleaseSemaphore increments list count and enables pending thread   */
    /*----------------------------------------------------------------------*/
    static DWORD PutNode(LIST * pList, NODE * pNode)
    {
    DWORD dwPrevCount;
        /* wait for ownership of list */
        WaitForSingleObject(pList->hMtx, INFINITE);
        if(pList->pFirst == NULL)           /* if empty list */
            pList->pFirst = pNode;          /*   set first ptr */
        else                                /* else set tail node ptr */
            pList->pLast->pNext = pNode;
        pList->pLast = pNode;               /* set last ptr */
        pNode->pNext = NULL;                /* reset next ptr */
        /* increment semaphore list count */
        ReleaseSemaphore(pList->hSem,1,&dwPrevCount);
        ReleaseMutex(pList->hMtx);          /* release ownership of list */
        return(dwPrevCount);
    }
    Last edited by rcgldr; 12-24-2016 at 04:50 PM.

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I'm sorry, I thought this was the C++ forum, not the C forum?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by Elysia View Post
    I'm sorry, I thought this was the C++ forum, not the C forum?
    Code:
    /*----------------------------------------------------------------------*/
    /*      mtcopy.cpp      multi-thread file copy demo                     */
    /*                                                                      */
    /*  Uses linked list fifo's to hold buffered data: LLIST.               */
    /*  Uses mutexes for ownership of link lists.                           */
    /*  Uses semaphores for list counts.                                    */
    /*                                                                      */
    /*  Uses the existing thread for file reads.                            */
    /*  Creates a second  thread for file writes.                           */
    /*----------------------------------------------------------------------*/
    #include <windows.h>
    #include <stdio.h>
    #include <stddef.h>
    #include <malloc.h>
    #include <memory.h>
    #include <string.h>
    #include <conio.h>
    
    #define NBFR    64                      /* number of buffers */
    #define BFRSZ   0x10000                 /* buffer size */
    
    typedef struct _NODE                    /* node structure */
    {
      struct _NODE *pNext;                  /* ptr to next node */
        BYTE       *pBfr;                   /* ptr to buffer */
        DWORD       dwCnt;                  /* # bytes in buffer */
    }NODE;
    
    typedef struct _LIST                    /* linked List structure */
    {
        NODE       *pFirst;                 /* ptr to 1st  node */
        NODE       *pLast;                  /* ptr to last node */
        HANDLE      hMtxSem[2];             /* mutex and semaphore handles */
    }LIST;
    #define hMtx hMtxSem[0]                 /* mutex        == ownership */
    #define hSem hMtxSem[1]                 /* semaphore    == list count */
    
    /*----------------------------------------------------------------------*/
    /*      data                                                            */
    /*----------------------------------------------------------------------*/
    static HANDLE   htT1;                   /* thread handles */
    static LIST     llT0;                   /* thread 0 list */
    static LIST     llT1;                   /* thread 1 list */
    static NODE     aNode[NBFR];            /* array of nodes */
    static DWORD    fExitThread;            /* flag to indicate thread exit */
    static DWORD    dwThreadT1;             /* thread id's (not used) */
    static DWORD    dwExitCode;             /* exit code */
    static HANDLE   hSrc;                   /* file I/O */
    static HANDLE   hDst;
    static PBYTE    pMem;                   /* ptr to allocated memory */
    /*----------------------------------------------------------------------*/
    /*      code                                                            */
    /*----------------------------------------------------------------------*/
    static DWORD    WINAPI Thread0(LPVOID);
    static DWORD    WINAPI Thread1(LPVOID);
    static void     InitThread0List(void);
    static NODE *   GetNode(LIST *);
    static long     PutNode(LIST *, NODE *);
    /*----------------------------------------------------------------------*/
    /*      main                                                            */
    /*----------------------------------------------------------------------*/
    DWORD main(DWORD argc, BYTE **argv)
    {
        hSrc    = INVALID_HANDLE_VALUE;     /* init file handles to not open */
        hDst    = INVALID_HANDLE_VALUE;
        if(argc != 3){
            printf("usage is mtcopy <src> <dst>\n");
            goto exit0;}
        pMem = (PBYTE)malloc(BFRSZ*NBFR);   /* allocate memory */
        if(!pMem){
            _cputs("can't allocate enough memory\r\n");
            goto exit0;}
        hSrc = CreateFile((LPCSTR)argv[1],  /* open src file */
                GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
        if(hSrc == INVALID_HANDLE_VALUE){
            printf("Can't open %s\n", argv[1]);
            goto exit0;}
        hDst = CreateFile((LPCSTR)argv[2],  /* open dst file */
            GENERIC_ALL , 0, NULL, CREATE_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, 0);
        if(hDst == INVALID_HANDLE_VALUE){
            printf("Can't create %s\n", argv[2]);
            goto exit0;}
        /*  create mutex and semaphore for each list */
        if((llT0.hSem = CreateSemaphore(NULL,0,NBFR+1,NULL))==NULL){
            _cputs("can't create semaphore\r\n");
            goto exit0;}
        if((llT0.hMtx = CreateMutex(NULL,FALSE,NULL))==NULL){
            _cputs("can't create mutex\r\n");
            goto exit0;}
        if((llT1.hSem = CreateSemaphore(NULL,0,NBFR+1,NULL))==NULL){
            _cputs("can't create semaphore\r\n");
            goto exit0;}
        if((llT1.hMtx = CreateMutex(NULL,FALSE,NULL))==NULL){
            _cputs("can't create mutex\r\n");
            goto exit0;}
        /*  create threads */
        htT1 = CreateThread(NULL, 0, Thread1, 0, 0, &dwThreadT1);
        if(!htT1){
            _cputs("can't create thread\r\n");
            goto exit0;}
        InitThread0List();                  /* init Thread 0 list */
        Thread0((LPVOID)NULL);              /* start Thread 0 */
    exit0:
        if(htT1){                           /* close thread */
            WaitForSingleObject(htT1, INFINITE);
            CloseHandle(htT1);}
        if(llT1.hSem){                      /* close mutex, semaphore */
            CloseHandle(llT1.hSem);}
        if(llT1.hMtx){
            CloseHandle(llT1.hMtx);}
        if(llT0.hSem){
            CloseHandle(llT0.hSem);}
        if(llT0.hMtx){
            CloseHandle(llT0.hMtx);}
        if(hDst != INVALID_HANDLE_VALUE){   /* close files */
            CloseHandle(hDst);}
        if(hSrc != INVALID_HANDLE_VALUE){
            CloseHandle(hSrc);}
        if(pMem){                           /* free memory */
            free(pMem);}
        return(0);
    }
    /*----------------------------------------------------------------------*/
    /*      Thread0         read bfr from file 0                            */
    /*----------------------------------------------------------------------*/
    static DWORD WINAPI Thread0(LPVOID lpvoid)
    {
    NODE *pNode;
        while(1){
            pNode = GetNode(&llT0);         /* get node */
            ReadFile(hSrc, pNode->pBfr, BFRSZ, &(pNode->dwCnt), NULL);
            PutNode(&llT1, pNode);          /* send node to thread 1 */
            if(pNode->dwCnt == 0){          /* exit if end of file */
                return(0);}}
    }
    /*----------------------------------------------------------------------*/
    /*      Thread1         write bfr to file 1                             */
    /*----------------------------------------------------------------------*/
    static DWORD WINAPI Thread1(LPVOID lpvoid)
    {
    NODE *pNode;
    DWORD dwWrite;
    DWORD dwCnt = 1;
        while(dwCnt){
            pNode = GetNode(&llT1);         /* get node */
            dwCnt = pNode->dwCnt;           /* localize count */
            if(dwCnt)                       /* write data if count != 0 */
                WriteFile(hDst, pNode->pBfr, dwCnt, &dwWrite, NULL);
            PutNode(&llT0, pNode);}         /* return node to thread 0 */
        return(0);
    }
    /*----------------------------------------------------------------------*/
    /*      InitThread0List init thread 0 list                              */
    /*----------------------------------------------------------------------*/
    static void InitThread0List(void)
    {
    BYTE * pBfr;
    DWORD i;
        pBfr = pMem;
        for(i = 0; i < NBFR; i++){
            aNode[i].pBfr = pBfr;
            PutNode(&llT0, &aNode[i]);
            pBfr += BFRSZ;}
    }
    /*----------------------------------------------------------------------*/
    /*      GetNode     get first node from list                            */
    /*                                                                      */
    /*  WaitForMultipleObjects eliminates any thread priority issues        */
    /*----------------------------------------------------------------------*/
    static NODE * GetNode(LIST * pList)
    {
    NODE * pNode;                           /* used for return value */
    /*  wait for ownership, node, and decrement semaphore count */
        WaitForMultipleObjects(2, pList->hMtxSem, TRUE ,INFINITE);
        pNode = pList->pFirst;              /* set return value */
        pList->pFirst = pNode->pNext;       /* advance first ptr */
        if(pList->pFirst == NULL)           /* if emptied list */
            pList->pLast = NULL;            /*  reset last ptr as well */
        ReleaseMutex(pList->hMtx);          /* release ownership of list */
        return(pNode);
    }
    /*----------------------------------------------------------------------*/
    /*      PutNode     append node to end of list                          */
    /*      returns 0 if list was previously empty                          */
    /*                                                                      */
    /*  ReleaseSemaphore increments list count and enables pending thread   */
    /*----------------------------------------------------------------------*/
    static long PutNode(LIST * pList, NODE * pNode)
    {
    long lPrevCount;
        /* wait for ownership of list */
        WaitForSingleObject(pList->hMtx, INFINITE);
        if(pList->pFirst == NULL)           /* if empty list */
            pList->pFirst = pNode;          /*   set first ptr */
        else                                /* else set tail node ptr */
            pList->pLast->pNext = pNode;
        pList->pLast = pNode;               /* set last ptr */
        pNode->pNext = NULL;                /* reset next ptr */
        /* increment semaphore list count */
        ReleaseSemaphore(pList->hSem,1,&lPrevCount);
        ReleaseMutex(pList->hMtx);          /* release ownership of list */
        return(lPrevCount);
    }

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    I did not mean just changing .c to .cpp. How can you justify that this is C++ code?

    It's stuffed full with C stuff:
    - #define instead of const.
    - typedef and low-level structurs with low-level buffers instead of abstracted high-level buffers
    - Tons of global variablers with C-style array and windows handles
    - Non-standard main! It should be "int main(int argc, char** argv)", nothing else!
    - printfs and gotos
    - malloc instead of new (but here you should use vector)
    - CreateFile instead of ifstream/ofstream
    - CreateSemaphore instead of std::mutex
    - CrrateMutex instead of std::mutex
    - Non-standard _cputs instead of std::cout
    - CreateThread instead of std::thread
    - C-style thread handlers instead of C++-style thread handlers
    - Pointers instead of references
    - ReadFile/WriteFile instead of oftream/istream/getline
    - Bad indentation

    These are some examples. This code belongs in the C forum, not here.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    Quote Originally Posted by Elysia View Post
    I did not mean just changing .c to .cpp. How can you justify that this is C++ code?
    I don't. The OP asked for working examples of multi-threaded code using Windows API, and the above is a working example. It's old code that I used as an example for another forum years ago, with minor updates. If the OP or anyone else was interested, the code could be changed to proper C++ code, but I don't have a need for it.
    Last edited by rcgldr; 12-26-2016 at 03:37 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Multi threading examples please
    By kingnoger in forum C++ Programming
    Replies: 1
    Last Post: 12-23-2016, 02:18 AM
  2. Using Multi-threading and/or Multi-process
    By lehe in forum C++ Programming
    Replies: 5
    Last Post: 07-14-2009, 11:43 AM
  3. Is Multi-threading necessary?
    By keira in forum Networking/Device Communication
    Replies: 2
    Last Post: 10-14-2007, 05:13 AM
  4. Multi-threading
    By justgotthis in forum Linux Programming
    Replies: 7
    Last Post: 10-08-2005, 10:28 AM

Tags for this Thread