首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多线程。如何平等分享共同资源?

多线程。如何平等分享共同资源?
EN

Stack Overflow用户
提问于 2016-07-08 15:55:52
回答 2查看 761关注 0票数 0

简单的代码(我知道这是一个非常糟糕的代码,但我只是为示例编写的):

代码语言:javascript
复制
 1 #include <mutex>
 2 #include <iostream>
 3 #include <thread>
 4 
 5 std::mutex mu;
 6 
 7 void myFunc(void) {
 8         for (int i = 0; i < 100; ++i) {
 9                 mu.lock();
 10                 std::cout << "CHILD Thread: " << std::this_thread::get_id() << std::endl;
 11                 mu.unlock();
 12         }
 13 }
 14 
 15 int main()
 16 {
 17         std::thread thr(myFunc);
 18         for (int i = 0; i < 100; ++i) {
 19                 mu.lock();
 20                 std::cout << "MAIN Thread: " << std::this_thread::get_id() << std::endl;
 21                 mu.unlock();
 22         }
 23         thr.join();
 24         return 0;
 25 }

返回此类输出:

代码语言:javascript
复制
1      MAIN Thread: 140581832210240
2      MAIN Thread: 140581832210240
3      MAIN Thread: 140581832210240
4      MAIN Thread: 140581832210240
5      MAIN Thread: 140581832210240
6      MAIN Thread: 140581832210240
7      MAIN Thread: 140581832210240
8      CHILD Thread: 140581814855424
9      CHILD Thread: 140581814855424
10     CHILD Thread: 140581814855424
11     CHILD Thread: 140581814855424
12     CHILD Thread: 140581814855424
13     CHILD Thread: 140581814855424
14     CHILD Thread: 140581814855424
15     CHILD Thread: 140581814855424
16     CHILD Thread: 140581814855424
17     CHILD Thread: 140581814855424
18     MAIN Thread: 140581832210240
19     MAIN Thread: 140581832210240
20     MAIN Thread: 140581832210240
21     MAIN Thread: 140581832210240
22     MAIN Thread: 140581832210240
23     CHILD Thread: 140581814855424
24     CHILD Thread: 140581814855424
25     CHILD Thread: 140581814855424
26     CHILD Thread: 140581814855424
27     CHILD Thread: 140581814855424
28     CHILD Thread: 140581814855424
29     CHILD Thread: 140581814855424
           ....... and so on

在我看来--这个输出违背了多线程的意义,因为一个线程必须等待另一个线程很长时间。这个输出应该同时给我的孩子的cout,cout的主,cout的孩子,cout的主等等。我知道互斥不是公平分享共同资源的责任,但那是谁呢?我如何在我的程序中实现这一点?

谢谢。

编辑:将std::cout放入函数:

代码语言:javascript
复制
10 void common_cout(string msg) {
11         mu.lock();
12         std::cout << msg << std::endl;
13         mu.unlock();
14 }

帮不上忙。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-07-08 22:03:43

原始代码在windows中也有相同的问题,但我切换到使用本机windows等效项,这个窗口示例的工作方式与您预期的一样,在两个线程之间交替使用。ReleaseMutex()的每个实例都会导致“其他”线程获取互斥并运行。主要而言,睡眠(2)是确保myFunc首先启动它的循环的一种简单方法。

我还为总共三个线程创建了一个主线程和两个线程的版本。循环按顺序进行,因此看起来Windows本机互斥锁是按照请求的顺序完成的。

对于循环类型或线程和/或进程之间的一般同步,每个线程或进程使用一个信号量更好,因为任何线程或进程都可以增加(释放/信号)任何信号量。这方面的问题是信号量不是标准线程接口的本机部分,需要一些互斥变量和条件变量的组合才能实现等效的信号量。Windows和posix支持本机信号量。

代码语言:javascript
复制
#include <iostream>
#include <windows.h>

static HANDLE mu;                       // handle: mutex
static HANDLE ht1;                      // handle: thread 1
static DWORD  id1;                      // thread 1 id

DWORD WINAPI myFunc(LPVOID) {
    for (int i = 0; i < 20; ++i) {
        WaitForSingleObject(mu, INFINITE);
        std::cout << "child thread: " << i << std::endl;
        ReleaseMutex(mu);
    }
    return 0;
}

int main()
{
    mu = CreateMutex(NULL,TRUE,NULL);   // main owns mutex
    ht1 = CreateThread(NULL, 0, myFunc, 0, 0, &id1);
    Sleep(2);                           // make sure myFunc running
    ReleaseMutex(mu);                   // release mutex
    for (int i = 0; i < 20; ++i) {
        WaitForSingleObject(mu, INFINITE);
        std::cout << "main  thread: " << i << std::endl;
        ReleaseMutex(mu);
    }
    WaitForSingleObject(ht1, INFINITE);
    CloseHandle(ht1);
    CloseHandle(mu);
    return 0;
}

输出

代码语言:javascript
复制
child thread: 0
main  thread: 0
child thread: 1
main  thread: 1
...
child thread: 18
main  thread: 18
child thread: 19
main  thread: 19

3个线程示例:

代码语言:javascript
复制
#include <iostream>
#include <windows.h>

static HANDLE mu;                       // handle: mutex
static HANDLE ht0;                      // handle: thread 0
static HANDLE ht1;                      // handle: thread 1
static DWORD  id0;                      // thread 0 id
static DWORD  id1;                      // thread 1 id

DWORD WINAPI Thread0(LPVOID) {
    for (int i = 0; i < 10; ++i) {
        WaitForSingleObject(mu, INFINITE);
        std::cout << "Thread0 : " << i << std::endl;
        ReleaseMutex(mu);
    }
    return 0;
}

DWORD WINAPI Thread1(LPVOID) {
    for (int i = 0; i < 10; ++i) {
        WaitForSingleObject(mu, INFINITE);
        std::cout << "Thread1 : " << i << std::endl;
        ReleaseMutex(mu);
    }
    return 0;
}

DWORD WINAPI Thread2(LPVOID) {
    for (int i = 0; i < 10; ++i) {
        WaitForSingleObject(mu, INFINITE);
        std::cout << "Thread2 : " << i << std::endl;
        ReleaseMutex(mu);
    }
    return 0;
}

int main()
{
    mu = CreateMutex(NULL,TRUE,NULL);   // main owns mutex
    ht0 = CreateThread(NULL, 0, Thread0, 0, 0, &id0);
    ht1 = CreateThread(NULL, 0, Thread1, 0, 0, &id1);
    Sleep(2);                           // let other threads get started
    ReleaseMutex(mu);                   // release mutex
    Thread2(0);
    WaitForSingleObject(ht0, INFINITE);
    WaitForSingleObject(ht1, INFINITE);
    CloseHandle(ht0);
    CloseHandle(ht1);
    CloseHandle(mu);
    return 0;
}

输出

代码语言:javascript
复制
Thread0 : 0
Thread1 : 0
Thread2 : 0
Thread0 : 1
Thread1 : 1
Thread2 : 1
...
Thread0 : 9
Thread1 : 9
Thread2 : 9
票数 1
EN

Stack Overflow用户

发布于 2016-07-08 16:09:46

我知道互斥不是公平分享共同资源的责任,但那是谁呢?

实际的调度是由操作系统完成的。

您还没有说过这是什么,但是通常不会在线程之间切换的频率过高,因为这样做效率很低(切换需要一些成本)。

换句话说,你对“公平”的想法--想必是严格的循环--每个线程轮流执行--这将是一种代价高昂的默认行为。无论如何,如果它是您想要的,您可以显式地对它进行编码。公平调度程序的通常目标是在运行的线程等待多长时间和在线程仍在执行(可能)有用的工作时抢占线程的频率之间进行某种权衡。

当然,操作系统的行为也取决于您有多少内核。你也没提过这个。

..。我如何在我的程序中实现这一点?

如果您在线程中做了一些合理的实际工作,您可能会发现您的调度程序的行为更符合您的喜好。这种人工测试很少给出有用的结果,特别是因为您在一个紧密的循环中执行少量的代码。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38270903

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档