Как передать параметры в потоки, которые уже запущены - PullRequest
0 голосов
/ 31 августа 2018

Привет У меня есть приложение, которое использует один поток для копирования буфера из *src в *dst, но я хочу, чтобы поток был запущен в начале программы. Когда я хочу использовать поток, я хочу передать *src, *dst и size потоку, чтобы он мог начать копировать буфер. Как мне этого добиться? Потому что, когда я запускаю поток, я передаю значения при создании экземпляра объекта, ThreadX при создании потока.

Thread^ t0 = gcnew Thread(gcnew ThreadStart(gcnew ThreadX(output, input, size), &ThreadX::ThreadEntryPoint));

Подводя итог, хочу сделать так:

  1. программа запускается
  2. создать тему
  3. ждать в теме
  4. передать параметры и разбудить поток, чтобы начать копирование
  5. как только копирование будет выполнено в потоке, тогда сообщите основному потоку, что это сделано
  6. незадолго до окончания программы присоединиться к потоку

Пример кода показан ниже.

Спасибо!

#include "stdafx.h"
#include <iostream>
#if 1

using namespace System;
using namespace System::Diagnostics;
using namespace System::Runtime::InteropServices;
using namespace System::Threading;

public ref class ThreadX
{
    unsigned short* destination;
    unsigned short* source;
    unsigned int num;

public:
    ThreadX(unsigned short* dstPtr, unsigned short* srcPtr, unsigned int size)
    {
        destination = dstPtr;
        source = srcPtr;
        num = size;
    }

    void ThreadEntryPoint()
    {
        memcpy(destination, source, sizeof(unsigned short)*num);
    }

};


int main()
{

    int size = 5056 * 2960 * 10; //iris 15 size
    unsigned short* input; //16bit
    unsigned short* output;
    Stopwatch^ sw = gcnew Stopwatch();

    input = new unsigned short[size];
    output = new unsigned short[size];

    //elapsed time for each test
    int sw0;
    int sw1;
    int sw2; 
    int sw3;

    //initialize input
    for (int i = 0; i < size; i++) { input[i] = i % 0xffff; }

    //initialize output
    for (int i = 0; i < size; i++) { output[i] = 0; }


    // TEST 1 //////////////////////////////////////////////////////////////////////
    for (int i = 0; i < size; i++) { output[i] = 0; }

    //-----------------------------------------------------------------------
    Thread^ t0 = gcnew Thread(gcnew ThreadStart(gcnew ThreadX(output, input, size), &ThreadX::ThreadEntryPoint));
    t0->Name = "t1";
    t0->Start();
    t0->Join();
    //-----------------------------------------------------------------------


    return 0
}

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

В принципе, вам нужны некоторые базовые строительные блоки для решения этой проблемы (я предполагаю, что вы хотите выполнить эту операцию копирования один раз. Мы можем легко расширить решение, если у вас есть постоянный поток входных данных):

1) Общая память - для обмена управляющей информацией. В этом случае это будет указатель исходного буфера, указатель целевого буфера и размер (от основного потока до рабочего потока). Вы также хотели бы, чтобы некоторая структура данных (давайте начнем с простого логического флага) обменивалась информацией в обратном направлении (от рабочего потока к основному потоку), когда работа завершена.

2) Условная переменная - для отправки сигнала из основного потока в рабочий поток и в обратном направлении. Итак, вам нужно 2 разных условных переменных.

3) Примитив синхронизации, такой как мьютекс, для защиты разделяемой памяти (поскольку к ним будут одновременно обращаться оба потока)

Учитывая эти строительные блоки, псевдокод вашей программы будет выглядеть так:

struct Control {
     void* src, *dest;
     int num_of_bytes = -1;
     bool isDone = false;
     conditional_var inputReceived;
     conditional_var copyDone;
     mutex m;
};

 void childThread() {
     m.lock();
     while (num_of_bytes == -1) {
         inputReceived.wait(m); // wait till you receive input.
     }
     // Input received. Make sure you set src and dest pointers, before setting num_of_bytes
     mempcy(dest, src, num_of_bytes);
     isDone = true; // mark work completion.
     copyDone.notify(); // notify the main thread of work completion.
     m.unlock();
}


void mainThread()
{
      // Create worker thread at start;
      thread_t thread = pthread_create(&childThread);

      // Do other stuff...
      //
      //

      // Input parameters received. Set control information, and notify the 
      //  workerthread.
      mutex.lock();
      src = input.src;
      dest = input.dest;
      num_of_bytes = input.num_of_bytes;

      inputReceived.notify(); // wake up worker thread.

      while (!isDone) { // Wait for copy to be over.
           copyDone.wait();
      }

      m.unlock();  // unlock the mutex.
      thread.join(); // wait for thread to join. If the thread has already ended before we execute thread join, it will return immediately.

}

Если вы хотите расширить это решение для обработки потока входных данных, мы можем использовать 2 очереди для запросов и ответов, причем каждый элемент очереди является входными и выходными параметрами.

0 голосов
/ 31 августа 2018

Не приостанавливать поток. Это плохой дизайн, и он может вызвать проблемы в будущем.

Вместо этого думайте об этом так: пусть поток block ожидает информацию о том, что он должен делать. Когда он получает эту информацию, он должен разблокировать, выполнить работу, а затем снова заблокировать, ожидая следующего.

Быстрый поиск «коллекции блокировок C #» обнаруживает класс BlockingCollection<T>, и это указывает на отмену одной из операций блокировки. Сделайте так, чтобы вы активировали CancellationToken, когда пришло время для выхода вашего потока, и заставили поток сидеть в ожидании операции блокировки, когда он не выполняет работу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...