Sub CutPaste()
Const cSheet As Variant = "Sheet1" ' Worksheet Name/Index
Const cFirstS As Variant = "E" ' Source First Column Letter/Number
Const cLastS As Variant = "O" ' Source Last Column Letter/Number
Const cFirstT As Variant = "D" ' Target First Column Letter/Number
Const cFirstRow As Long = 1 ' First Row Number
Const cCriteria As Variant = "B" ' Criteria Column Letter/Number
Const cStrCriteria As String = "Plan" ' Criteria String
Dim lastRow As Long ' Last Row Number
Dim i As Long ' Row Counter
With ThisWorkbook.Worksheets(cSheet)
lastRow = .Cells(.Rows.Count, cFirstS).End(xlUp).Row
For i = cFirstRow To lastRow
If .Cells(i, cCriteria) = cStrCriteria Then
.Range(.Cells(i, cFirstS), .Cells(i, cLastS)).Cut _
Destination:=.Cells(i, cFirstT)
End If
Next
End With
End Sub
Sub CopyClearContents()
Const cSheet As Variant = "Sheet1" ' Worksheet Name/Index
Const cFirstS As Variant = "E" ' Source First Column Letter/Number
Const cLastS As Variant = "O" ' Source Last Column Letter/Number
Const cFirstT As Variant = "D" ' Target First Column Letter/Number
Const cFirstRow As Long = 1 ' First Row Number
Const cCriteria As Variant = "B" ' Criteria Column Letter/Number
Const cStrCriteria As String = "Plan" ' Criteria String
Dim lastRow As Long ' Last Row Number
Dim i As Long ' Row Counter
With ThisWorkbook.Worksheets(cSheet)
lastRow = .Cells(.Rows.Count, cFirstS).End(xlUp).Row
For i = cFirstRow To lastRow
If .Cells(i, cCriteria) = cStrCriteria Then
.Range(.Cells(i, cFirstS), .Cells(i, cLastS)).Copy _
Destination:=.Cells(i, cFirstT)
.Cells(i, cLastS).ClearContents
End If
Next
End With
End Sub
Постепенное уменьшение переменной (между потоками) немного опасно, если не покончили Interlocked.Decrement
, но тот подход должен быть прекрасным, если у Вас есть последний поток (т.е. когда это добирается для обнуления), генерируют событие. Обратите внимание, что это должно было бы быть в "наконец" блок, чтобы не проигрывать, это в случае исключений (плюс Вы не хотят уничтожать процесс).
В "Параллельных Расширениях" (или с.NET 4.0), Вы могли бы также посмотреть на Parallel.ForEach
опции здесь..., которые могли бы быть другим способом получить все сделанное как блок. Не имея необходимость наблюдать их всех вручную.
Если его не больше чем 64 Потока для ожидания на можно использовать WaitHandle. Метод WaitAll как это:
List<WaitHandle> events = new List<WaitHandle>();
for (int i = 0; i < 64; i++)
{
ManualResetEvent mre = new ManualResetEvent(false);
ThreadPool.QueueUserWorkItem(
delegate(object o)
{
Thread.Sleep(TimeSpan.FromMinutes(1));
((ManualResetEvent)o).Set();
},mre);
events.Add(mre);
}
WaitHandle.WaitAll(events.ToArray());
Выполнение будет ожидать, пока все ManualResetEvents не установлены, альтернативно, можно использовать метод WaitAny.
Методы WaitAny и WaitAll заблокируют выполнение, но можно просто использовать список или словарь ManualResetEvents, связанного с задачей, которая является икрой для более позднего определения, если поток сделан все же.
Существует, не встроенный способ сделать это в данный момент - я нахожу это одной из самых больших болей об использовании потоков пула.
Как Marc говорит, это - вид материала, который фиксируется в параллельных Расширениях/.NET 4.0.
Не могли Вы давать каждому потоку отличный ManualResetEvent и каждый устанавливать событие при выполнении. Затем в основном потоке можно ожидать на всех событиях, переданных в.
Решение Marc является лучшим, если Вы просто хотите знать, когда все задания закончены и не нужны в более прекрасной информации, чем тот (как, кажется, Ваш случай).
Если бы Вы хотели, чтобы некоторый поток породил задания и некоторый другой поток к получить уведомления, то Вы могли использовать WaitHandle. Код намного длиннее.
int length = 10;
ManualResetEvent[] waits = new ManualResetEvent[length];
for ( int i = 0; i < length; i++ ) {
waits[i] = new ManualResetEvent( false );
ThreadPool.QueueUserWorkItem( (obj) => {
try {
} finally {
waits[i].Set();
}
} );
}
for ( int i = 0; i < length; i++ ) {
if ( !waits[i].WaitOne() )
break;
}
Метод WaitOne, как записано, всегда возвращает true, но я записал это как этот, чтобы заставить Вас помнить, что некоторые перегрузки берут Тайм-аут в качестве аргумента.
Что относительно того, чтобы использовать Семафор, и установленный предел к нему так же как Ваш пул потоков. Имейте метод, чтобы выбрать Семафор, быть названными, когда Вы запускаете свой поток, выпускаете его, когда Ваш конец потока и генерирует событие при приведении в рабочее состояние всего Семафора.