19 May '13 - 19:04 *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length
 
   Home   Help Search Login Register  
Pages: [1]
  Reply  |  Print  
Author Topic: BASS_Encode_Start/Stop is not thread safety  (Read 575 times)
Gorath
Posts: 63


« on: 11 May '12 - 14:12 »
Reply with quoteQuote

Sample code:
#include "stdafx.h"
#include <stdio.h>
#include "bass.h"
#include "bassenc.h"

DWORD WINAPI threadproc(LPVOID lpParam);

int Count = 10;
int m_switch = -1;
HANDLE staticlock;
int recHandle = 0;

int _tmain(int argc, _TCHAR* argv[])
{
  if (!BASS_Init(0, 44100, 0, NULL, NULL)) {
    printf("Can't initialize output device.\n");
    getchar();
    return 1;
  }
  staticlock = CreateMutex(NULL, FALSE, NULL);
  if (!(recHandle = BASS_StreamCreate(44100, 2, BASS_STREAM_DECODE, NULL, NULL))) {
    printf("Failed to create dummy stream.\n");
    getchar();
    return 1;
  }
  printf("BASS_GetVersion: %x\n", BASS_GetVersion());
  printf("BASS_Encode_GetVersion: %x\n", BASS_Encode_GetVersion());
  for (int i = 0; i < Count; i++) {
    CreateThread(NULL, 0, threadproc, (LPVOID)(i), 0, NULL);
  }
  int k = 0;
  while (true) {
    Sleep(1000);
    if (!WaitForSingleObject(staticlock, INFINITE)) {
      m_switch = 0;
      ReleaseMutex(staticlock);
    }
    printf("Case %d\n", ++k);
  }
  getchar();
  return 0;
}

DWORD WINAPI threadproc(LPVOID lpParam) {
  int i = (int)lpParam;
  int handle = 0;
  while (1) {
    int found = 0;
    if (!WaitForSingleObject(staticlock, INFINITE)) {
      if (m_switch == i) {
        found = 1;
        ++m_switch;
      }
      ReleaseMutex(staticlock);
    }
    if (found) {
      if (handle) {
        BASS_Encode_Stop(handle);
        if (BASS_ErrorGetCode())
          printf("BASS_Encode_Stop: %d, %d\n", handle, BASS_ErrorGetCode());
      }
      handle = BASS_Encode_Start(recHandle, "lame -x -r -b 128 -h - ", BASS_ENCODE_PAUSE | BASS_ENCODE_NOHEAD, 0, 0);
      if (BASS_ErrorGetCode())
        printf("BASS_Encode_Start: %d, %d\n", handle, BASS_ErrorGetCode());
    }
    Sleep(1);
  }
}

Description: Create 20 threads and each second stop last encoder and start new. All is in infinite loop and should produce no error.
Sample output from Win7 32bit, Core-i5, 4cores:
BASS_GetVersion: 2040902
BASS_Encode_GetVersion: 2040901
Case 1
Case 2
Case 3
Case 4
Case 5
BASS_Encode_Stop: 212, 5
Case 6
Case 7
Case 8
BASS_Encode_Stop: 228, 5
Case 9
BASS_Encode_Stop: 328, 5
Case 10
Case 11
Case 12
BASS_Encode_Stop: 220, 5
Case 13
Case 14
BASS_Encode_Stop: 276, 5
Case 15
Case 16
Case 17
Case 18
Case 19
Case 20
Case 21
Case 22
Case 23
Case 24
BASS_Encode_Stop: 352, 5
Case 25
Case 26
Case 27
Case 28
BASS_Encode_Stop: 248, 5
Case 29
BASS_Encode_Stop: 252, 5
Case 30
Case 31
Case 32
Case 33
BASS_Encode_Stop: 284, 5
Case 34
Case 35
Case 36
Case 37
Case 38
Case 39
Case 40
Case 41
Case 42
BASS_Encode_Stop: 280, 5
Case 43
Case 44
BASS_Encode_Stop: 284, 5
Case 45
Case 46
Case 47
Case 48
Case 49
Case 50
BASS_Encode_Stop: 200, 5
Case 51
Case 52
Case 53
Case 54
Case 55
Case 56
Case 57
Case 58
Case 59
Case 60
Case 61
Case 62
Case 63
Case 64
Case 65
Case 66
Case 67
Case 68
Case 69
Case 70
Case 71
Case 72
Case 73
BASS_Encode_Stop: 332, 5
Case 74
Case 75
BASS_Encode_Stop: 336, 5
Case 76
Case 77
Case 78
BASS_Encode_Stop: 332, 5
Case 79

BASS_ERROR_HANDLE(5) randomly occurs at output what means that BASS_Encode_Start/Stop is not thread safety.

Can you look at it?

Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #1 on: 11 May '12 - 17:21 »
Reply with quoteQuote

I think the problem there is related to the fact that the returned handle is the encoder process handle when using an external encoder, eg. the LAME process handle in this case. So a new encoder can have the same handle as a previously freed encoder, and if the new encoder happens to be created in the middle of the BASS_Encode_Stop call to free the old encoder with the same handle, then the new encoder might be immediately freed in that call too. Here's an update to try, in which BASS_Encode_Stop will only ever free one encoder if an encoder handle (rather than channel handle) is used...

   www.un4seen.com/stuff/bassenc.dll

Let me know if you still see any problem with it.
Logged
Gorath
Posts: 63


« Reply #2 on: 14 May '12 - 08:33 »
Reply with quoteQuote

I tried new version and I haven't get BASS_ERROR_HANDLE anymore, but application could crash Sad
Unhandled exception at 0x772d1742 in BassProblem_C.exe: 0xC0000264:  The application attempted to release a resource it did not own. Click OK to terminate the application.
Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #3 on: 14 May '12 - 15:13 »
Reply with quoteQuote

For some clues on what went wrong, please provide any details that you have on the crash, eg. a call-stack, etc.
Logged
Gorath
Posts: 63


« Reply #4 on: 14 May '12 - 18:21 »
Reply with quoteQuote

That crash was made on app with the same source code what I paste as sample code, compiled with VS2010 under Win7 32bit. I did the same test on my laptop with WinXp (VS2008) and BASS_Encode_Start hangup thread.
Logged
Ian @ un4seen
Administrator
Posts: 15244


« Reply #5 on: 15 May '12 - 14:48 »
Reply with quoteQuote

Oh yes, I see it now. There was a silly bug in the modification above (trying to release a lock that wasn't held). Here's another update to correct that...

   www.un4seen.com/stuff/bassenc.dll

Let me know if you still have any trouble with it.
Logged
Gorath
Posts: 63


« Reply #6 on: 16 May '12 - 15:06 »
Reply with quoteQuote

No problem.
Logged
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.18 | SMF © 2013, Simple Machines