Возможно, необходимо рассмотреть использование HashSet.
Из ссылки MSDN:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
HashSet evenNumbers = new HashSet();
HashSet oddNumbers = new HashSet();
for (int i = 0; i < 5; i++)
{
// Populate numbers with just even numbers.
evenNumbers.Add(i * 2);
// Populate oddNumbers with just odd numbers.
oddNumbers.Add((i * 2) + 1);
}
Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
DisplaySet(evenNumbers);
Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
DisplaySet(oddNumbers);
// Create a new HashSet populated with even numbers.
HashSet numbers = new HashSet(evenNumbers);
Console.WriteLine("numbers UnionWith oddNumbers...");
numbers.UnionWith(oddNumbers);
Console.Write("numbers contains {0} elements: ", numbers.Count);
DisplaySet(numbers);
}
private static void DisplaySet(HashSet set)
{
Console.Write("{");
foreach (int i in set)
{
Console.Write(" {0}", i);
}
Console.WriteLine(" }");
}
}
/* This example produces output similar to the following:
* evenNumbers contains 5 elements: { 0 2 4 6 8 }
* oddNumbers contains 5 elements: { 1 3 5 7 9 }
* numbers UnionWith oddNumbers...
* numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }
*/
Джозеф, в ответ на ваш последний вопрос:
Когда пользователь создает «нормальный» новый процесс, который выполняется fork (). В этом случае ядру вообще не нужно беспокоиться о создании нового стека, потому что новый процесс является полной копией старого, вплоть до стека.
Если пользователь заменяет текущий запущенный процесс используя exec (), тогда ядру действительно нужно создать новый стек - но в этом случае это легко, потому что оно начинает с чистого листа. exec () стирает пространство памяти процесса и повторно инициализирует его, поэтому ядро может сказать «после exec (), потому что тогда наши два процесса будут топать друг друга в стеке. Ядро также не может просто поместить его в место по умолчанию (как это делает exec ()), потому что это место уже занято в этом пространстве памяти. Единственное решение - позволить вызывающему процессу найти для него место, что он и делает.
потому что тогда наши два процесса будут топать друг друга в стеке. Ядро также не может просто поместить его в место по умолчанию (как это делает exec ()), потому что это место уже занято в этом пространстве памяти. Единственное решение - позволить вызывающему процессу найти для него место, что он и делает.Вам нужен флаг MAP_ANONYMOUS для mmap. И MAP_GROWSDOWN, поскольку вы хотите использовать его в качестве стека.
Что-то вроде:
void *stack = mmap(NULL,initial_stacksize,PROT_WRITE|PROT_READ,MAP_PRIVATE|MAP_GROWSDOWN|MAP_ANONYMOUS,-1,0);
Дополнительную информацию см. На странице руководства mmap. И помните, клонирование - это концепция низкого уровня, которую вы не должны использовать, если вам действительно не нужно то, что она предлагает. И он предлагает много возможностей управления - например, настройку собственного стека - на случай, если вы захотите немного обмануть (например, сделать стек доступным во всех связанных процессах). Если у вас нет веских причин использовать clone, используйте fork или pthreads.
mmap - это больше, чем просто отображение файла в памяти. Фактически, некоторые реализации malloc будут использовать mmap для больших распределений. Если вы прочтете прекрасную страницу руководства, вы заметите флаг MAP_ANONYMOUS, и вы увидите, что вам совсем не нужно предоставлять дескриптор файла.
Что касается того, почему ядро не может просто «найти кучу бесплатных memory ", ну, если вы хотите, чтобы кто-то делал эту работу за вас, используйте вместо него fork или pthreads.
Note that the clone
system call doesn't take an argument for the stack location. It actually works just like fork
. It's just the glibc wrapper which takes that argument.
Вот код, который отображает область стека и инструктирует системный вызов clone использовать эту область в качестве стека.
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
int execute_clone(void *arg)
{
printf("\nclone function Executed....Sleeping\n");
fflush(stdout);
return 0;
}
int main()
{
void *ptr;
int rc;
void *start =(void *) 0x0000010000000000;
size_t len = 0x0000000000200000;
ptr = mmap(start, len, PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED|MAP_GROWSDOWN, 0, 0);
if(ptr == (void *)-1)
{
perror("\nmmap failed");
}
rc = clone(&execute_clone, ptr + len, CLONE_VM, NULL);
if(rc <= 0)
{
perror("\nClone() failed");
}
}