0

My device is a camera.

I want to be able to start thread one, and run something similar to a state machine for a device one in that thread. Same thing for device two.

So far I have all the control functions written for the device. I can run them in two different threads completely fine. What I need to do is be able to control them from the main thread.

For my control thread I created a while loop that is always true unless an atomic reference to a variable is passed that corresponds to break loop.

What I want to do from the main thread, is to send a command to thread one saying to capture a frame. It takes 10ms to capture a frame. Half way through capturing the first frame I want to send a command to thread two to capture a frame and keep on doing so.

void classA::Capture(WINUSB_INTERFACE_HANDLE * handle, std::atomic<int>& cap)
{
    std::vector<byte> frame;

    while (true) 
    {
        if (cap == 1) 
        {
            frame = CaptureFrame(*handle);
            cap = 0;
        }
        else if (cap == 2)
    }
}

void ClassA::run()
{
    std::vector<WINUSB_INTERFACE_HANDLE> devices  = GetHandles();

    Initialize(devices[0]);
    Initialize(devices[1]);

    WINUSB_INTERFACE_HANDLE h1 = devices[0];
    WINUSB_INTERFACE_HANDLE h2 = devices[1];

    std::atomic<int> cap1{ 0 };
    std::atomic<int> cap2{ 0 };

    std::thread t1(&ClassA::Capture,this, &h1, &n1, ref(cap1));
    std::thread t2(&ClassA::Capture,this, &h2, &n2, ref(cap2));

    for (int c = 0; c < 2000; c++)
    {
        if (c % 2 == 0)
        {
            cap1 = 1;
            Sleep(5);
        }
        else
        {
            cap2 = 1;
            Sleep(5);
        }
    }

    cap1 = 2;
    cap2 = 2;
    t1.join();
    t2.join();

}

What ends up happening is, sometimes devices work in the right order and grab frames like so 121212, but sometimes a device will skip and do this 1211221. (by 1 i mean device one, 2 device 2, capturing order)

After looking around I found std::queue but I'm not sure how I can implement it. Thank you very much. I am sorry for the confusion. Any help is appreciated.

2 Answers2

0

You likely have a race condition between the two threads. The CaptureFrame in one thread doesn't finish before being call in the second thread.

If the order is important then why have two threads? Why not have a single thread that just calls CaptureFrame repeatedly?

If you do need two threads then checkout out std::mutex. You can synchronize the two threads so that only one is active at any point.

If you need one thread to start while the other is still active then check out nanosleep for Linux or similar for Windows. Regular sleep is to imprecise for your use case.

Matthew Fisher
  • 2,258
  • 2
  • 14
  • 23
  • I thought that when i call a function i call a copy of it. Meaning i can call it multiple times and run it in parallel. I dont want them to run one after the other, but each thread half way through the operation of the other. Im trying to capture frames from the second camera while the first camera is still in the process of capturing a frame. Thank you for a reply! –  Aug 21 '18 at 02:13
  • added some more ideas based on your comment – Matthew Fisher Aug 21 '18 at 02:21
  • Thank you, i will look into using something more precisie than sleep. –  Aug 21 '18 at 02:28
  • I did. My reputation is too low, so it's not publicly displayed. –  Aug 21 '18 at 02:44
0

If it's absolutely vital to maintain the "121212" order of frame capture, then you're going to need more than you have. In particular, both capture threads will need to wait for their 10 ms heartbeat, but they'll also need to ensure that the other camera has captured a frame.

You have the basis of this correct, in that you have the correct threads doing the tasks involved, however those threads will need to be a bit more sophisticated. This will be pseudo code rather than actual C++, but it should provide a basis.

You need four "Events" - these could be done using raw Win32 EVENT's, alternatively for a platform agnostic version, a std::mutex and a std::condition_variable will get the job done. The Events are capture1 capture2 started1 and started2. capture Events are used by the main thread to trigger a frame capture, started Events inform the main thread that the appropriate capture thread has actually started capturing a frame.

Main control code:

// create all four events.

std::thread t1(&ClassA::Capture,this, &h1, &n1, ref(trigger1), ref(started1));
std::thread t2(&ClassA::Capture,this, &h2, &n2, ref(trigger2), ref(started2)); 

for (int c = 0; c < 2000; c++)
{
    PostEvent(trigger1);
    WaitForEvent(started1);
    Sleep(5);
    PostEvent(trigger2);
    WaitForEvent(started2);
    Sleep(5);
}

And then your thread loop looks something like this:

void classA::Capture(WINUSB_INTERFACE_HANDLE * handle, Event& trigger, Event& started)
{
    std::vector<byte> frame;

    while (true) 
    {
        WaitForEvent(trigger);
        PostEvent(started);
        // Did you really mean to return the frame as a vector<byte> by value?
        // That's not going to perform well, consider passing frame by reference into CaptureFrame()
        frame = CaptureFrame(*handle);
    }
}

Standard disclaimers apply: this code has not been compiled, and probably won't compile as is: you need that Event object to make it work.

dgnuff
  • 3,195
  • 2
  • 18
  • 32
  • Thank you! this is a great idea! I will familiarize myself with std::mutex and a std::condition_variable and start trying to implement this as soon as i can. Yes i agree i should have passed it by reference. Its okay i didnt need a working example, what you have given me is more than enough! thank you very much! –  Aug 21 '18 at 02:17