嗨,我有一个应用程序,使用一个线程将缓冲区从*src
复制到*dst
,但我希望在程序开始时启动线程。当我想使用线程时,我想将*src
,*dst
和size
传递给线程,以便它可以开始复制缓冲区。我该如何实现这一目标?因为当我启动一个线程时,我在创建一个线程时实例化对象ThreadX
时传递值。
Thread^ t0 = gcnew Thread(gcnew ThreadStart(gcnew ThreadX(output, input, size), &ThreadX::ThreadEntryPoint));
总结一下,我想这样做:
示例代码如下所示。
谢谢!
#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
}
基本上,你需要一些基本的构建块来解决这个问题(我假设你只想执行一次这种复制操作。如果你有一个恒定的输入流,我们可以很容易地扩展解决方案):
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个队列来处理请求和响应,队列的每个元素都是输入和输出参数。
不要暂停线程。这是糟糕的设计,很有可能会引发你的问题。
相反,可以这样想:让线程阻塞等待它应该做什么的信息。当它获得该信息时,它应该解锁,完成工作,然后再次阻止等待下一件事。
快速搜索“C#阻塞集合”揭示了BlockingCollection<T>
类,并且这个guide取消了其中一个阻塞操作。使它在您的线程退出时激活CancellationToken,并让线程在阻塞操作不能正常工作时等待。