Thread Problem mit Sockets und Threads - IRC-Gateway (14 answers)
Opened by Paul321 at 2011-08-08 15:06

topeg
 2011-08-09 03:09
#151360 #151360
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Beispiel für eine verwaltete Kommunikation zwischen zwei Threads:

more (26.8kb):
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/perl
use warnings;
use strict;

use threads;
use threads::shared;

# Daten für die Threads
my %threads=();
# für jeden thread gibt es drei Werte,
# die über den thread hinaus gelesen werden können
# end       => thread hat sich beenden, oder soll sich beenden
# txt_print => Puffer für den anzuzeigenden Text
# txt_send  => Puffer für den "eingebenden" Text

#-----------------------------------------------------------------------
# Daten Thread A
share($threads{a}{end});
share($threads{a}{txt_print});
share($threads{a}{txt_send});
$threads{a}{end}=0;
$threads{a}{txt_print}='';
$threads{a}{txt_send}='';

$threads{a}{name}='Thread_A';
$threads{a}{'shift'}=0;

#-----------------------------------------------------------------------
# Daten Thread B
share($threads{b}{end});
share($threads{b}{txt_print});
share($threads{b}{txt_send});
$threads{b}{end}=0;
$threads{b}{txt_print}='';
$threads{b}{txt_send}='';

$threads{b}{name}='Thread_B';
$threads{b}{'shift'}=35;

#-----------------------------------------------------------------------
# Thread a starten
$threads{a}{thread}=threads->new(\&work,$threads{a});

# Thread b starten
$threads{b}{thread}=threads->new(\&work,$threads{b});

# haupttread loop
# hier werden die Nachrichten verteilt
# solange arbeiten wie ein Thread noch läuft.
while(1)
{
  my $exit=0;

  my($n1,$n2)=qw(a b);

  communicate($threads{a},$threads{b});
  communicate($threads{b},$threads{a});

  last if($threads{a}{end} || $threads{b}{end});

  # ein wenig warten
  sleep(1);
}

# Beenden erzwingen
# und auf das Ende warten
$threads{a}{end}=1;
$threads{b}{end}=1;
$threads{a}{thread}->join();
$threads{b}{thread}->join();

exit;
########################################################################
########################################################################

# das ist der einzelne Thread
sub work
{
  my $data=shift;

  # mindestens 10 maxinal 20 Durchläufe
  my $count=int(rand(10))+10;

  while(1)
  {
    # zufälliger String von 10 Zeichen länge
    my $str=join('',map{chr(33+int(rand(93)))}(0..10));

    # Text an den Puffer anhängen
    # beim überschreiben könnten Daten verloren gehen,
    # wenn der Puffer noch nicht geleert wurde
    $data->{txt_send}.="$str\n";

    # es soll Text angezeigt werden
    if($data->{txt_print})
    {
      # Text lesen und "Puffer" leeren
      # das sollte möglichst atomar sein,
      # sonst könnte ein anderer Thread da zwischen funken
      my $text=$data->{txt_print};
      $data->{txt_print}='';

      # Ausgabe
      # Text formatieren
      my $shift=' 'x$data->{'shift'};
      $text=~s/\n$//s;
      $text=~s/(^|\n)/$1$shift$data->{name}: /gs;
      print "$text\n";
    }

    # wenn counter abgelaufen
    # dann Signal zum beenden setzen
    $data->{end}=1 if($count-- <= 0);

    # beenden wenn das Signal kommt
    last if($data->{end});

    # zufällig lang warten (0..1 Sekunde)
    select(undef,undef,undef,rand(1));
  }
}

# Daten wischen den einzelnen Kind-Threads austauschen
sub communicate
{
  my ($from,$to)=@_;

  # wenn Text gesendet wurde
  # dann formatieren und an den anderen senden
  if($from->{txt_send})
  {
    # EingabePuffer lesen und leeren
    my $text=$from->{txt_send};
    $from->{txt_send}='';

    # formatieren und in AusgabePuffer schreiben
    $text=~s/\n$//s;
    $text=~s/(^|\n)/$1$from->{name} => /gs;
    $to->{txt_print}.="$text\n";
  }

  # beenden Nachricht senden wenn nötig
  if($from->{end} && !$from->{end_ok})
  {
    $to->{txt_print}.="$from->{name} hat sich beendet!\n";
    $from->{end_ok}=1;
  }
}

View full thread Problem mit Sockets und Threads - IRC-Gateway