使用线程读取输入时缺少字符

时间:2017-02-28 01:27:02

标签: multithreading perl file stdin

我们假设我们有一个打开文件的脚本,然后逐行读取并将该行打印到终端。我们有一个sigle线程和一个多线程版本。

问题在于两个脚本的结果输出几乎相同,但不完全是。在多线程版本中,大约有十行错过了前两个字符。我的意思是,如果真正的线条是" Stackoverflow摇滚",我获得" ackoverflow rocks"。

我认为这与一些竞争条件有关,因为如果我调整参数来创造很多小工人,我会得到更多的错误,而不是如果我使用更少和更大的工人。

单线程是这样的:

$file = "some/file.txt";
open (INPUT, $file) or die "Error: $!\n";

while ($line = <STDIN>) {
    print $line;
}

多线程版本使用线程队列,此实现基于@ikegami方法:

use threads            qw( async );
use Thread::Queue 3.01 qw( );

use constant NUM_WORKERS    => 4;
use constant WORK_UNIT_SIZE => 100000;

sub worker {
    my ($job) = @_;
    for (@$job) {
        print $_;
    }
}

my $q = Thread::Queue->new();


async { while (defined( my $job = $q->dequeue() )) { worker($job); } }
    for 1..NUM_WORKERS;

my $done = 0;    

while (!$done) {
    my @lines;

    while (@lines < WORK_UNIT_SIZE) {
        my $line = <>;
        if (!defined($line)) {
            $done = 1;
            last;
        }

    push @lines, $line;
}

$q->enqueue(\@lines) if @lines;
}

$q->end();
$_->join for threads->list;

1 个答案:

答案 0 :(得分:4)

我尝试了你的程序,得到了类似的(错误的)结果。 Thread::Semaphore使用lock print而不是use threads; use threads::shared; ... my $mtx : shared; sub worker { my ($job) = @_; for (@$job) { lock($mtx); # (b)locks print $_; # autom. unlocked here } } ... ,而不是$mtx,因为它比T :: S更简单,例如:

undef

全局变量lock充当互斥锁。它的价值并不重要,即使lock(就像这里)也可以。 对for的调用会阻止并仅在其他线程当前没有锁定该变量时返回。 当它超出范围时,它会自动解锁(从而使{…}返回)。在此示例中发生 在print循环的每次迭代之后;没有额外的print阻止。

现在我们已同步use threads; use threads::shared; ... my $mtx : shared; $| = 1; # force unbuffered output sub worker { # as above } ... 次来电话......

但是这也没有用,因为lock确实缓冲了I / O(好吧,只有O)。所以我强制无缓冲输出:

    Sub CheckSpecialCharacters()
    'This macro looks for any characters above 255 and tags them with the appropriate existing language character.

        Dim ch As Range: Set ch = ActiveDocument.Characters(1)

        Do

            Counter = Counter + 1

            ch.Select

            myValue = AscW(Selection.Text)
            If myValue > 255 Then

                If (myValue > 8190 And myValue < 8225) Or (myValue > 288 And myValue < 381) Or (myValue > 701 And myValue < 704) Or myValue = 730 Then
                    'Ignores Curly Quotes and Transliteration punctuation

                ElseIf (myValue > 7935 And myValue < 8192) Or (myValue > 879 And myValue < 1024) Then
                    'Greek Characters get langgrk applied
                    Selection.Expand unit:=wdWord
                    Selection.Style = "langgrk"

                ElseIf (myValue > 1423 And myValue < 1535) Then
                    'Hebrew Characters get langheb applied
                    Selection.Expand unit:=wdWord
                    Selection.Style = "langheb"

                ElseIf myValue > 7679 And myValue < 7830 Then
                    'Extended transliteration characters get langtrans applied //OLD VALUES// (myValue > 288 And myValue < 381) Or (myValue > 701 And myValue < 704)
                    If HCCP = True Then Selection.Expand unit:=wdWord
                    Selection.Style = "langtrans"

                ElseIf (myValue > 19968 And myValue < 40959) Then
                    'Chinese Characters get langchin applied
                    Selection.Expand unit:=wdWord
                    Selection.Style = "langchin"

                ElseIf (myValue > 19968 And myValue < 40917) Then
                    'Japanese Characters get langjap applied
                    Selection.Expand unit:=wdWord
                    Selection.Style = "langjap"

                Else
                    If HCCP = True Then Selection.Expand unit:=wdWord
                    Selection.Style = "lang"

                End If

            End If

DoNext:


End Sub

然后它奏效了。令我惊讶的是,我可以移除!==,它仍然有效。也许是偶然的。请注意,如果没有缓冲,您的脚本运行速度会明显变慢。

我的结论是:你是threads::shared