编辑:忘了说程序必须在.NET 3.5中; Visual Studio 2008和Windows 7。
在我的旧MSDN库(针对Visual Studio 2008)文档中,我遇到了一篇关于C#中的线程的文章。我尝试转换为C ++ / CLI。我在转换中遇到了很多问题。现在只剩下一个:C3371: Cannot take the address of 'Producer::ThreadRun' unless creating delegate instance
。
原始文档的标题:如何:同步生产者和消费者线程(C#编程指南)
我在在线MSDN库中找不到原始文档。好像它已被删除。我也无法在网络上找到它。
在文档中,代码包含:
嗯,这是C#中的原始代码:
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
public class SyncEvents
{
public SyncEvents()
{
_newItemEvent = new AutoResetEvent(false);
_exitThreadEvent = new ManualResetEvent(false);
_eventArray = new WaitHandle[2];
_eventArray[0] = _newItemEvent;
_eventArray[1] = _exitThreadEvent;
}
public EventWaitHandle ExitThreadEvent
{
get { return _exitThreadEvent; }
}
public EventWaitHandle NewItemEvent
{
get { return _newItemEvent; }
}
public WaitHandle[] EventArray
{
get { return _eventArray; }
}
private EventWaitHandle _newItemEvent;
private EventWaitHandle _exitThreadEvent;
private WaitHandle[] _eventArray;
}
public class Producer
{
public Producer(Queue<int> q, SyncEvents e)
{
_queue = q;
_syncEvents = e;
}
// Producer.ThreadRun
public void ThreadRun()
{
int count = 0;
Random r = new Random();
while (!_syncEvents.ExitThreadEvent.WaitOne(0, false))
{
lock (((ICollection)_queue).SyncRoot)
{
while (_queue.Count < 20)
{
_queue.Enqueue(r.Next(0, 100));
_syncEvents.NewItemEvent.Set();
count++;
}
}
}
Console.WriteLine("Producer thread: produced {0} items", count);
}
private Queue<int> _queue;
private SyncEvents _syncEvents;
}
public class Consumer
{
public Consumer(Queue<int> q, SyncEvents e)
{
_queue = q;
_syncEvents = e;
}
// Consumer.ThreadRun
public void ThreadRun()
{
int count = 0;
while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
{
lock (((ICollection)_queue).SyncRoot)
{
int item = _queue.Dequeue();
}
count++;
}
Console.WriteLine("Consumer Thread: consumed {0} items", count);
}
private Queue<int> _queue;
private SyncEvents _syncEvents;
}
public class ThreadSyncSample
{
private static void ShowQueueContents(Queue<int> q)
{
lock (((ICollection)q).SyncRoot)
{
foreach (int item in q)
{
Console.Write("{0, 2} ", item);
}
}
Console.WriteLine();
}
static void Main()
{
Queue<int> queue = new Queue<int>();
SyncEvents syncEvents = new SyncEvents();
Console.WriteLine("Configuring worker threads...");
Producer producer = new Producer(queue, syncEvents);
Consumer consumer = new Consumer(queue, syncEvents);
Thread producerThread = new Thread(producer.ThreadRun);
Thread consumerThread = new Thread(consumer.ThreadRun);
Console.WriteLine("Launching producer and consumer threads...");
producerThread.Start();
consumerThread.Start();
for (int i = 0; i < 4; i++)
{
Thread.Sleep(2500);
ShowQueueContents(queue);
}
Console.WriteLine("Signaling threads to terminate...");
syncEvents.ExitThreadEvent.Set();
producerThread.Join();
consumerThread.Join();
}
}
我已转换为以下C ++ / CLI。请注意
Producer::ThreadRun
中获得WaitOne功能lock
和Monitor::Enter
Monitor::Exit
main()
gcnew Thread(&Producer::ThreadRun)
中的编译错误
Producer::ThreadRun
的地址。C ++ / CLI中的代码:
using namespace System;
using namespace System::Threading;
using namespace System::Collections;
using namespace System::Collections::Generic;
public ref class SyncEvents
{
public:
property System::Threading::EventWaitHandle ^ _newItemEvent;
property System::Threading::EventWaitHandle ^ _exitThreadEvent;
property array<System::Threading::WaitHandle ^> ^ _eventArray;
public:
SyncEvents()
{
_newItemEvent = gcnew System::Threading::AutoResetEvent(false);
_exitThreadEvent = gcnew System::Threading::ManualResetEvent(false);
_eventArray = gcnew array<System::Threading::WaitHandle ^>(2);
_eventArray[0] = _newItemEvent;
_eventArray[1] = _exitThreadEvent;
}
};
public ref class Producer
{
private:
System::Collections::Generic::Queue<int> ^ _queue;
SyncEvents ^ _syncEvents;
public:
Producer(System::Collections::Generic::Queue<int> ^ q, SyncEvents ^ e)
{
_queue = q;
_syncEvents = e;
}
void ThreadRun()
{
int count = 0;
Random ^ r = gcnew Random();
while (!_syncEvents->_exitThreadEvent->WaitOne(0, false))
{
Monitor::Enter(((System::Collections::ICollection ^)_queue)->SyncRoot);
try
{
while (_queue->Count < 20)
{
_queue->Enqueue(r->Next(0, 100));
_syncEvents->_newItemEvent->Set();
count++;
}
}
finally
{
Monitor::Exit(((System::Collections::ICollection ^)_queue)->SyncRoot);
}
}
Console::WriteLine("Producer thread: produced {0} items", count);
}
};
public ref class Consumer
{
private:
System::Collections::Generic::Queue<int> ^ _queue;
SyncEvents ^ _syncEvents;
public:
Consumer(System::Collections::Generic::Queue<int> ^ q, SyncEvents ^ e)
{
_queue = q;
_syncEvents = e;
}
void ThreadRun()
{
int count = 0;
while (System::Threading::WaitHandle::WaitAny(_syncEvents->_eventArray) != 1)
{
Monitor::Enter(((System::Collections::ICollection ^)_queue)->SyncRoot);
try
{
int item = _queue->Dequeue();
}
finally
{
Monitor::Exit(((System::Collections::ICollection ^)_queue)->SyncRoot);
}
count++;
}
Console::WriteLine("Consumer Thread: consumed {0} items", count);
}
};
static void ShowQueueContents(System::Collections::Generic::Queue<int> ^ _q)
{
Monitor::Enter(((System::Collections::ICollection ^)_q)->SyncRoot);
try
{
for each (int item in _q)
Console::WriteLine("{0, 3} ", item);
}
finally
{
Monitor::Exit(((System::Collections::ICollection ^)_q)->SyncRoot);
}
};
int main()
{
System::Collections::Generic::Queue<int> ^ queue
= gcnew System::Collections::Generic::Queue<int>();
SyncEvents ^ syncEvents = gcnew SyncEvents();
Console::WriteLine("Configuring worker threads...");
Producer ^ producer = gcnew Producer(queue, syncEvents);
Consumer ^ consumer = gcnew Consumer(queue, syncEvents);
System::Threading::Thread ^ producerThread = gcnew System::Threading::Thread(&Producer::ThreadRun);
System::Threading::Thread ^ consumerThread = gcnew System::Threading::Thread(&Consumer::ThreadRun);
Console::WriteLine("Launching producer and cosumer threads...");
producerThread->Start();
consumerThread->Start();
for (int i = 0; i < 4; i++)
{
Thread::Sleep(2500);
ShoqQueueuContents(queue);
}
Console::WriteLine("Signaling threads to terminate...");
syncEvents->_exitThreadEvent->Set();
producerThread->Join();
consumerThread->Join();
}
答案 0 :(得分:3)
System::Threading::Thread ^ producerThread =
gcnew System::Threading::Thread(&Producer::ThreadRun);
Thread类构造函数需要委托对象。您习惯于自动将方法转换为委托的C#语言语法糖。但是在C ++ / CLI中不存在这种糖,你必须自己创建委托对象。并且要明确目标对象和目标方法,C#编译器想要推断目标对象。这确实为C ++ / CLI语言提供了一些C#所没有的功能,代价是必须编写更强大的代码:
System::Threading::Thread ^ producerThread =
gcnew System::Threading::Thread(
gcnew System::Threading::ThreadStart(producer, &Producer::ThreadRun)
);
请考虑.NET 4中针对这些场景的现有支持,例如BlockingCollection&lt;&gt;和ConcurrentQueue&lt;&gt;。