C++ 终止C+中的线程+;从另一个线程

C++ 终止C+中的线程+;从另一个线程,c++,windows,multithreading,primes,C++,Windows,Multithreading,Primes,基本上我是在寻找有两个线程的素数。我将每个线程的可能素数的范围一分为二,或者在线程之间静态地分配范围。然而,必须处理较小数字的线程将不可避免地在计算较大数字的线程之前完成。我想做的是,一旦任何一个线程通过它的范围,终止两个线程,然后将未完成的线程范围的剩余部分的一半交给完成的线程,这样它们就会递归地平衡,并始终并行运行。 例:A(1-100)和B(100-200),A先完成,而B仍在150。两者都停止,A像A(150-175)一样开始,B像B(175-200)一样开始 以下是我目前的代码: #i

基本上我是在寻找有两个线程的素数。我将每个线程的可能素数的范围一分为二,或者在线程之间静态地分配范围。然而,必须处理较小数字的线程将不可避免地在计算较大数字的线程之前完成。我想做的是,一旦任何一个线程通过它的范围,终止两个线程,然后将未完成的线程范围的剩余部分的一半交给完成的线程,这样它们就会递归地平衡,并始终并行运行。 例:A(1-100)和B(100-200),A先完成,而B仍在150。两者都停止,A像A(150-175)一样开始,B像B(175-200)一样开始

以下是我目前的代码:

#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
priority_queue<int> primes;
CRITICAL_SECTION critical;
struct args
{
    int begin;
    int end;
}par1, par2;

int e_prosto(int n)
{
    for(int i = 2; i*i<(n + 1) ; i++)
    if (n & 1 == 0 || n % i == 0) return 0;
    return 1;
}

unsigned int __stdcall rabotnik(void* n)
{
    struct args *lPar = (args*) n;
    for(int i = lPar->begin; i < lPar->end; i++)
    {
        if(e_prosto(i)){
            EnterCriticalSection(&critical);
            primes.push(i);
            LeaveCriticalSection(&critical);
        }
    }
    return 0;
}

int main()
{
    int foo;
    printf(" Tarsene na prosti do: ");
    scanf("%d", &foo);
    par1.begin=1;
    par1.end=foo/2+1;
    par2.begin=foo/2+1;
    par2.end=foo;

    HANDLE hvadkaA, hvadkaB;
    InitializeCriticalSection(&critical);
    SYSTEMTIME st, now, then;

    hvadkaA = (HANDLE)_beginthreadex(0, 0, &rabotnik, (void*)&par1, 0, 0);
    hvadkaB = (HANDLE)_beginthreadex(0, 0, &rabotnik, (void*)&par2, 0, 0);
    ::GetSystemTime(&then);
    WaitForSingleObject(hvadkaA, INFINITE);
    WaitForSingleObject(hvadkaB, INFINITE);

    CloseHandle(hvadkaA);
    CloseHandle(hvadkaB);

    ::GetSystemTime(&now);
    while(!primes.empty())
    {
        printf("%d \t", primes.top());
        primes.pop();
    }
    printf("\nGotov za %d milisec", abs(now.wMilliseconds - then.wMilliseconds));
    system("pause>nul");
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
优先级队列素数;
临界段临界;
结构参数
{
int开始;
内端;
}par1,par2;
内部e_prosto(内部n)
{
for(inti=2;i*ibegin;iend;i++)
{
如果(e_prosto(i)){
EnterCriticalSection(&critical);
素数推(i);
LeaveCriticalSection(&critical);
}
}
返回0;
}
int main()
{
int foo;
printf(“Tarsene na prosti do:”);
scanf(“%d”和&foo);
par1.begin=1;
par1.end=foo/2+1;
par2.begin=foo/2+1;
par2.end=foo;
处理hvadkaA、hvadkaB;
初始化关键部分(&critical);
系统时间,现在,然后;
hvadkaA=(HANDLE)_beginthreadex(0,0和rabotnik,(void*)和par1,0,0);
hvadkaB=(HANDLE)_beginthreadex(0,0和rabotnik,(void*)和par2,0,0);
::GetSystemTime(&then);
WaitForSingleObject(hvadkaA,无限);
WaitForSingleObject(hvadkaB,无限);
闭合手柄(hvadkaA);
闭合手柄(hvadkaB);
::GetSystemTime(&now);
而(!primes.empty())
{
printf(“%d\t”,primes.top());
primes.pop();
}
printf(“\nGotov za%d毫秒”,abs(now.wmillseconds-then.wmillseconds));
系统(“暂停>nul”);
返回0;
}

暴力终止线程是个坏主意,因为它会使进程处于不良状态。如果线程在循环中运行,您可以在外部设置一些标志,线程可以测试并决定是否终止自身(这可以通过简单地退出thead函数来完成)。记住用互斥锁保护你的旗帜


您可能还想看看其他一些模式。您可能希望将您的素数范围放入队列中。然后,每个工作线程可以从队列中提取值并执行搜索。通过这种方式,您可以在不终止和重新启动线程的情况下平均分配负载。

您的主要查找算法效率极低,但我想现在谈谈这一点

线程:

为每个线程设置作业队列。。杀死/终止短生命线程,特别是对于prime查找,听起来是一个非常糟糕的主意


避免争论。不要对
素数使用锁定。按(i)。为每个线程设置一个单独的队列,将结果推送到那里。当线程完成该范围时,输入criticalsection并合并结果。这样你几乎不需要锁。

我建议,给每个线程分配一个模块A(1-100)和B(101-200),每个线程分配一个模。例如,A将采用所有奇数索引,B将采用所有偶数索引,结果是A{1,3,5,7,9,…,191193197199}和B{2,4,6,8,…,190192194198200}。这可能是实现线程负载平衡的最快、最简单的方法,因为计算的复杂性是均匀分布的

下一个建议是添加一个bool,指示是否可以继续处理。然后,在开始每次计算之前,检查是否可以继续。通过这种方式,您可以停止计算而不终止线程,代价是每个循环额外进行一次比较

#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
bool run;
priority_queue<int> primes;
CRITICAL_SECTION critical;
struct args
{
    int begin;
    int end;
}par1, par2;

int e_prosto(int n)
{
    for(int i = 2; i*i<(n + 1) ; i++)
    if (n & 1 == 0 || n % i == 0) return 0;
    return 1;
}

unsigned int __stdcall rabotnik(void* n)
{
    struct args *lPar = (args*) n;
    for(int i = lPar->begin; i < lPar->end && run; i++)
    {
        if(e_prosto(i)){
            EnterCriticalSection(&critical);
            primes.push(i);
            LeaveCriticalSection(&critical);
        }
    }
    run = false;
    return 0;
}

int main()
{
    int foo;
    printf(" Tarsene na prosti do: ");
    scanf("%d", &foo);
    par1.begin=1;
    par1.end=foo/2+1;
    par2.begin=foo/2+1;
    par2.end=foo;
    run = true;

    HANDLE hvadkaA, hvadkaB;
    InitializeCriticalSection(&critical);
    SYSTEMTIME st, now, then;

    hvadkaA = (HANDLE)_beginthreadex(0, 0, &rabotnik, (void*)&par1, 0, 0);
    hvadkaB = (HANDLE)_beginthreadex(0, 0, &rabotnik, (void*)&par2, 0, 0);
    ::GetSystemTime(&then);
    WaitForSingleObject(hvadkaA, INFINITE);
    WaitForSingleObject(hvadkaB, INFINITE);

    CloseHandle(hvadkaA);
    CloseHandle(hvadkaB);

    ::GetSystemTime(&now);
    while(!primes.empty())
    {
        printf("%d \t", primes.top());
        primes.pop();
    }
    printf("\nGotov za %d milisec", abs(now.wMilliseconds - then.wMilliseconds));
    system("pause>nul");
    return 0;
}
一旦另一个堆栈为空,您就必须处理一个堆栈中剩余的值(或者在每个堆栈的底部放置一个-1,这样,如果其中一个堆栈为空,那么所有大于-1的值都将被打印)

另一种解决方案是维护一个已排序的素数列表,每当线程返回时都会更新该列表。然后,可以将其复制到PAR结构中,用于更快的质数检测(如果一个数可由现有素数均匀地分割,那么该数不是素数)。
注意:我还没有测试过这些示例,不过它们应该足够接近您的总体想法。

为每个线程设置作业队列更有意义。。杀死/终止短生命线程,特别是对于prime查找,这听起来是一个非常糟糕的主意。。你这样做仅仅是为了练习线程吗?是的,我今天刚刚研究了线程,这是一个练习运行sieve多线程似乎是一个更有趣的练习。一位朋友建议使用sieve进行prime查找,但我们不知道如何使用它,因为两个线程共享变量,并且不需要经常锁定和解锁
#include <windows.h>
#include <stdio.h>
#include <process.h>
#include <queue>
#include <cmath>
#include <iostream>
using namespace std;
priority_queue<int> primes;
CRITICAL_SECTION critical;
typedef struct args
{
    int begin;
    int end;

    //Helper method for initalizing struct
    void setAll(int inBegin, bool inEnd)
    {
    }

} *PArgs;

int e_prosto(int n)
{
    for(int i = 2; i*i<(n + 1) ; i++)
    if (n & 1 == 0 || n % i == 0) return 0;
    return 1;
}

static DWORD WINAPI rabotnik(LPVOID lpParam)
{
    struct args *lPar = (args*) lpParam;
    for(int i = lPar->begin; i < lPar->end; i++)
    {
        if(e_prosto(i)){
            EnterCriticalSection(&critical);
            primes.push(i);
            LeaveCriticalSection(&critical);
        }
    }
    return 0;
}

int main()
{
    const int NUM_THREAD = 2;           //Use named constant incase you want to change later.
    DWORD returnedThreadID;
    DWORD threadID[NUM_THREAD];
    HANDLE threadHandle[NUM_THREAD];    //Holds the handels for the threads.
    int foo,                            //Range size.
        fooBlockSize,                   //Number of elements in a block.
        nextBlock;
    PArgs par[NUM_THREAD];

    printf(" Tarsene na prosti do: ");
    scanf("%d", &foo);                  //Get range size from user.
    fooBlockSize = foo / (NUM_THREAD * 10); //Set number of elements in a block.

    InitializeCriticalSection(&critical);
    SYSTEMTIME st, now, then;

    for (int i = 0; i < NUM_THREAD; i++) 
    {
        par[i] = (PArgs) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PArgs)); 
           // If the allocation fails, the system is out of memory so terminate execution.
        if( par[i] == NULL ){ cout<<"par HeapAlloc failed with error# "<<GetLastError()<<endl<<"Will now quit."<<endl; ExitProcess(2);}
    }

    for(int i = 0; i < NUM_THREAD; i++)
    {
        par[i]->begin = (fooBlockSize * i) + 1;
        par[i]->end = par[i]->begin + fooBlockSize;
        threadHandle[i] = CreateThread(NULL, 0, rabotnik, par[i], CREATE_SUSPENDED, &threadID[i]);
    }
    nextBlock = NUM_THREAD;

    ::GetSystemTime(&then);
    for (int i = 0; i < NUM_THREAD; i++)
    {
        ResumeThread(threadHandle[i]);      //Start threads
    }

    while( ((fooBlockSize * nextBlock) + 1) < foo)
    {
        returnedThreadID = WaitForMultipleObjects(NUM_THREAD, threadHandle, false, INFINITE);   //Wait for a thread to complete.
        for(int i = 0; i<NUM_THREAD;i++)
        {
            if(returnedThreadID = threadID[i])
            {
                //Update the thread's arguments with the new block.
                par[i]->begin = (fooBlockSize * nextBlock) + 1;
                par[i]->end = par[i]->begin + fooBlockSize;

                //Restart the thread.
                ResumeThread(threadHandle[i]);
                nextBlock++;
            }
        }
    }

    for (int i = 0; i < NUM_THREAD; i++)
    {
        //Return heap memorry (good practice, though Windows should return it all when the process terminates).
        if (HeapFree(GetProcessHeap(), 0, par[i]) == 0)
        {
            cout<<"HeapFree failed for par["<<i<<"]"<<endl;
        }

        //Not sure we need to close the threads, but it was in original version.
        CloseHandle(threadHandle[i]);
    }

    ::GetSystemTime(&now);
    while(!primes.empty())
    {
        printf("%d \t", primes.top());
        primes.pop();
    }
    printf("\nGotov za %d milisec", abs(now.wMilliseconds - then.wMilliseconds));
    system("pause>nul");
    return 0;
}
    while(!primes1.empty() && !primes2.empty())
    {
        if(primes1.top() > primes2.top())
        {
            printf("%d \t", primes1.top());
            primes1.pop();
        }
        else
        {
            printf("%d \t", primes2.top());
            primes2.pop();
        }
    }